diff options
Diffstat (limited to '')
679 files changed, 167189 insertions, 0 deletions
diff --git a/connectivity/source/commontools/AutoRetrievingBase.cxx b/connectivity/source/commontools/AutoRetrievingBase.cxx new file mode 100644 index 000000000..d1170fdd9 --- /dev/null +++ b/connectivity/source/commontools/AutoRetrievingBase.cxx @@ -0,0 +1,51 @@ +/* -*- 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> + +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 OUString sTableName = sStmt.getToken(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 000000000..591fe961e --- /dev/null +++ b/connectivity/source/commontools/BlobHelper.cxx @@ -0,0 +1,71 @@ +/* -*- 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> + +using namespace connectivity; +using namespace dbtools; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +BlobHelper::BlobHelper(const css::uno::Sequence< sal_Int8 >& _val) : m_aValue(_val) +{ +} + +::sal_Int64 SAL_CALL BlobHelper::length( ) +{ + return m_aValue.getLength(); +} + +css::uno::Sequence< ::sal_Int8 > SAL_CALL BlobHelper::getBytes( ::sal_Int64 pos, ::sal_Int32 _length ) +{ + if ( sal_Int32(pos + _length) > m_aValue.getLength() ) + throw css::sdbc::SQLException(); + return css::uno::Sequence< ::sal_Int8 >(m_aValue.getConstArray() + sal_Int32(pos),_length); +} + +css::uno::Reference< css::io::XInputStream > SAL_CALL BlobHelper::getBinaryStream( ) +{ + return new ::comphelper::SequenceInputStream(m_aValue); +} + + +// The "return" after a call to throwFeatureNotImplementedSQLException() +// (which always throws) will be detected as unreachable when doing +// global inlining. + +SAL_WNOUNREACHABLE_CODE_PUSH + +::sal_Int64 SAL_CALL BlobHelper::position( const css::uno::Sequence< ::sal_Int8 >& /*pattern*/, ::sal_Int64 /*start*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::position", *this ); + return 0; +} + +::sal_Int64 SAL_CALL BlobHelper::positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& /*pattern*/, ::sal_Int64 /*start*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::positionOfBlob", *this ); + return 0; +} + +SAL_WNOUNREACHABLE_CODE_POP + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/CommonTools.cxx b/connectivity/source/commontools/CommonTools.cxx new file mode 100644 index 000000000..5c84bf6e6 --- /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 <tools/diagnose_ex.h> + +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(16); + rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(processID.getArray()) ); + processID.realloc(17); + processID[16] = 0; + + 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,const OUString& _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,const OUString& _rSpecials) +{ + + return ( ((c >= 97) && (c <= 122)) || ((c >= 65) && (c <= 90)) || ((c >= 48) && (c <= 57)) || + c == '_' || _rSpecials.indexOf(c) != -1); +} + + +bool isValidSQLName(const OUString& rName,const OUString& _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,const OUString& _rSpecials) +{ + if(isValidSQLName(rName,_rSpecials)) + return rName; + + const sal_Unicode* pStr = rName.getStr(); + // if not valid + if (*pStr >= 128 || rtl::isAsciiDigit(*pStr)) + return OUString(); + + OUStringBuffer aNewName(rName); + sal_Int32 nLength = rName.getLength(); + for (sal_Int32 i=0; i < nLength; ++i) + if(!isCharOk(aNewName[i],_rSpecials)) + aNewName[i] = '_'; + + return aNewName.makeStringAndClear(); +} + +OUString quoteName(const OUString& _rQuote, const OUString& _rName) +{ + OUString sName = _rName; + if( !_rQuote.isEmpty() && _rQuote.toChar() != ' ') + sName = _rQuote + _rName + _rQuote; + return sName; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/ConnectionWrapper.cxx b/connectivity/source/commontools/ConnectionWrapper.cxx new file mode 100644 index 000000000..d7d999058 --- /dev/null +++ b/connectivity/source/commontools/ConnectionWrapper.cxx @@ -0,0 +1,239 @@ +/* -*- 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 <cppuhelper/typeprovider.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[ 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 (isUnoTunnelId<OConnectionWrapper>(rId)) + return reinterpret_cast< sal_Int64 >( this ); + + if(m_xUnoTunnel.is()) + return m_xUnoTunnel->getSomething(rId); + return 0; +} + + +Sequence< sal_Int8 > OConnectionWrapper::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +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 + std::sort(_rInfo.begin(),_rInfo.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 000000000..510736cc6 --- /dev/null +++ b/connectivity/source/commontools/DateConversion.cxx @@ -0,0 +1,526 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <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 <tools/diagnose_ex.h> + + +using namespace ::connectivity; +using namespace ::comphelper; +using namespace ::com::sun::star::script; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::dbtools; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::uno; + +OUString DBTypeConversion::toSQLString(sal_Int32 eType, const Any& _rVal, + const Reference< XTypeConverter >& _rxTypeConverter) +{ + OUStringBuffer aRet; + if (_rVal.hasValue()) + { + try + { + switch (eType) + { + case DataType::INTEGER: + case DataType::BIT: + case DataType::BOOLEAN: + case DataType::TINYINT: + case DataType::SMALLINT: + if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_BOOLEAN) + { + if (::cppu::any2bool(_rVal)) + aRet.append("1"); + else + aRet.append("0"); + } + else + { + OUString sTemp; + _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp; + aRet.append(sTemp); + } + break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + aRet.append("'"); + { + OUString aTemp; + _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= aTemp; + sal_Int32 nIndex = sal_Int32(-2); + const OUString sQuot("\'"); + do + { + nIndex += 2; + nIndex = aTemp.indexOf(sQuot,nIndex); + if(nIndex != -1) + aTemp = aTemp.replaceAt(nIndex,sQuot.getLength(), "\'\'"); + } while (nIndex != -1); + + aRet.append(aTemp); + } + aRet.append("'"); + break; + case DataType::REAL: + case DataType::DOUBLE: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::BIGINT: + default: + { + OUString sTemp; + _rxTypeConverter->convertToSimpleType(_rVal, TypeClass_STRING) >>= sTemp; + aRet.append(sTemp); + } + break; + case DataType::TIMESTAMP: + { + DateTime aDateTime; + bool bOk = false; + if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE) + { + double nValue = 0.0; + _rVal >>= nValue; + aDateTime = DBTypeConversion::toDateTime(nValue); + bOk = true; + } + else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING) + { + OUString sValue; + _rVal >>= sValue; + aDateTime = DBTypeConversion::toDateTime(sValue); + bOk = true; + } + else + bOk = _rVal >>= aDateTime; + + OSL_ENSURE( bOk, "DBTypeConversion::toSQLString: _rVal is not datetime!"); + // check if this is really a timestamp or only a date + if ( bOk ) + { + aRet.append("{ts '"); + aRet.append(DBTypeConversion::toDateTimeString(aDateTime)); + aRet.append("'}"); + break; + } + break; + } + case DataType::DATE: + { + Date aDate; + bool bOk = false; + if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE) + { + double nValue = 0.0; + _rVal >>= nValue; + aDate = DBTypeConversion::toDate(nValue); + bOk = true; + } + else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING) + { + OUString sValue; + _rVal >>= sValue; + aDate = DBTypeConversion::toDate(sValue); + bOk = true; + } + else + bOk = _rVal >>= aDate; + OSL_ENSURE( bOk, "DBTypeConversion::toSQLString: _rVal is not date!"); + aRet.append("{d '"); + aRet.append(DBTypeConversion::toDateString(aDate)); + aRet.append("'}"); + } break; + case DataType::TIME: + { + css::util::Time aTime; + bool bOk = false; + if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_DOUBLE) + { + double nValue = 0.0; + _rVal >>= nValue; + aTime = DBTypeConversion::toTime(nValue); + bOk = true; + } + else if (_rVal.getValueType().getTypeClass() == css::uno::TypeClass_STRING) + { + OUString sValue; + _rVal >>= sValue; + aTime = DBTypeConversion::toTime(sValue); + bOk = true; + } + else + bOk = _rVal >>= aTime; + OSL_ENSURE( bOk,"DBTypeConversion::toSQLString: _rVal is not time!"); + aRet.append("{t '"); + aRet.append(DBTypeConversion::toTimeString(aTime)); + aRet.append("'}"); + } break; + } + } + catch ( const Exception& ) + { + OSL_FAIL("TypeConversion Error"); + } + } + else + aRet.append(" NULL "); + return aRet.makeStringAndClear(); +} + +Date DBTypeConversion::getNULLDate(const Reference< XNumberFormatsSupplier > &xSupplier) +{ + OSL_ENSURE(xSupplier.is(), "getNULLDate : the formatter doesn't implement a supplier !"); + if (xSupplier.is()) + { + try + { + // get the null date + Date aDate; + xSupplier->getNumberFormatSettings()->getPropertyValue("NullDate") >>= aDate; + return aDate; + } + catch ( const Exception& ) + { + } + } + + return getStandardDate(); +} + +void DBTypeConversion::setValue(const Reference<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& ) + { + OSL_FAIL("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 000000000..9d2ab8a47 --- /dev/null +++ b/connectivity/source/commontools/DriversConfig.cxx @@ -0,0 +1,237 @@ +/* -*- 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/DriversConfig.hxx> +#include <tools/wldcrd.hxx> +#include <comphelper/sequence.hxx> + +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(const uno::Reference< uno::XComponentContext >& _rxORB) +:m_xORB(_rxORB) +{ +} + + +DriversConfig::~DriversConfig() +{ +} + + +DriversConfig::DriversConfig( const DriversConfig& _rhs ) +{ + *this = _rhs; +} + + +DriversConfig& DriversConfig::operator=( const DriversConfig& _rhs ) +{ + if ( this != &_rhs ) + { + m_aNode = _rhs.m_aNode; + } + return *this; +} + + +OUString DriversConfig::getDriverFactoryName(const OUString& _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.sDriverFactory; + sOldPattern = rPattern; + } + } + + return sRet; +} + +OUString DriversConfig::getDriverTypeDisplayName(const OUString& _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(const OUString& _sURL) const +{ + return impl_get(_sURL,1); +} + +const ::comphelper::NamedValueCollection& DriversConfig::getFeatures(const OUString& _sURL) const +{ + return impl_get(_sURL,0); +} + +const ::comphelper::NamedValueCollection& DriversConfig::getMetaData(const OUString& _sURL) const +{ + return impl_get(_sURL,2); +} + +const ::comphelper::NamedValueCollection& DriversConfig::impl_get(const OUString& _sURL,sal_Int32 _nProps) const +{ + const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB); + const ::comphelper::NamedValueCollection* pRet = nullptr; + OUString sOldPattern; + for(const auto& [rPattern, rDriver] : rDrivers) + { + WildCard aWildCard(rPattern); + if ( sOldPattern.getLength() < rPattern.getLength() && aWildCard.Matches(_sURL) ) + { + switch(_nProps) + { + case 0: + pRet = &rDriver.aFeatures; + break; + case 1: + pRet = &rDriver.aProperties; + break; + case 2: + pRet = &rDriver.aMetaData; + break; + } + sOldPattern = rPattern; + } + } // for(;aIter != aEnd;++aIter) + if ( pRet == nullptr ) + { + static const ::comphelper::NamedValueCollection s_sEmpty; + pRet = &s_sEmpty; + } + return *pRet; +} + +uno::Sequence< OUString > DriversConfig::getURLs() const +{ + const TInstalledDrivers& rDrivers = m_aNode->getInstalledDrivers(m_xORB); + return comphelper::mapKeysToSequence(rDrivers); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx new file mode 100644 index 000000000..7d3d34891 --- /dev/null +++ b/connectivity/source/commontools/FDatabaseMetaDataResultSet.cxx @@ -0,0 +1,894 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <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/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/dbexception.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_aStatement(nullptr) + ,m_nColPos(0) + ,m_bBOF(true) + ,m_bEOF(true) +{ + construct(); +} + + +ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet( MetaDataResultSetType _eType ) + :ODatabaseMetaDataResultSet_BASE(m_aMutex) + ,::comphelper::OPropertyContainer(ODatabaseMetaDataResultSet_BASE::rBHelper) + ,m_aStatement(nullptr) + ,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 = nullptr; + m_xMetaData.clear(); + m_aRowsIter = m_aRows.end(); + m_aRows.clear(); + m_aRowsIter = m_aRows.end(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::acquire() throw() +{ + ODatabaseMetaDataResultSet_BASE::acquire(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::release() throw() +{ + 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(const ORows& _rRows) +{ + m_aRows = _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 ); +#if !(defined(_MSC_VER) && defined(ENABLE_LTO)) + assert(false); + return 0; // Never reached +#endif +} + +void ODatabaseMetaDataResultSet::checkIndex(sal_Int32 columnIndex ) +{ + if(columnIndex >= static_cast<sal_Int32>((*m_aRowsIter).size()) || columnIndex < 1) + ::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 bool(getValue(columnIndex)); +} + + +sal_Int8 SAL_CALL ODatabaseMetaDataResultSet::getByte( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +Sequence< sal_Int8 > SAL_CALL ODatabaseMetaDataResultSet::getBytes( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +css::util::Date SAL_CALL ODatabaseMetaDataResultSet::getDate( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +double SAL_CALL ODatabaseMetaDataResultSet::getDouble( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +float SAL_CALL ODatabaseMetaDataResultSet::getFloat( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getInt( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getRow( ) +{ + return 0; +} + + +sal_Int64 SAL_CALL ODatabaseMetaDataResultSet::getLong( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +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); +} + + +OUString SAL_CALL ODatabaseMetaDataResultSet::getString( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +css::util::Time SAL_CALL ODatabaseMetaDataResultSet::getTime( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +css::util::DateTime SAL_CALL ODatabaseMetaDataResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isAfterLast( ) +{ + return m_bEOF; +} + + +SAL_WNOUNREACHABLE_CODE_PUSH + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +SAL_WNOUNREACHABLE_CODE_POP + + +void SAL_CALL ODatabaseMetaDataResultSet::beforeFirst( ) +{ + ::dbtools::throwFunctionSequenceException(*this); +} + +void SAL_CALL ODatabaseMetaDataResultSet::afterLast( ) +{ + ::dbtools::throwFunctionSequenceException(*this); +} + + +void SAL_CALL ODatabaseMetaDataResultSet::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + } + dispose(); +} + + +SAL_WNOUNREACHABLE_CODE_PUSH + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::first( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 /*row*/ ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 /*row*/ ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +SAL_WNOUNREACHABLE_CODE_POP + + +Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( ) +{ + return m_aStatement.get(); +} + + +SAL_WNOUNREACHABLE_CODE_PUSH + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( ) +{ + ::dbtools::throwFunctionSequenceException(*this); + return false; +} + +SAL_WNOUNREACHABLE_CODE_POP + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isBeforeFirst( ) +{ + return m_bBOF; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::next( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + if ( m_bBOF ) + { + m_aRowsIter = m_aRows.begin(); + m_bBOF = false; + } + else + { + if ( m_bEOF ) + throwFunctionSequenceException( *this ); + else + if ( m_aRowsIter != m_aRows.end() ) + ++m_aRowsIter; + } + + bool bSuccess = m_aRowsIter != m_aRows.end(); + if ( !bSuccess ) + { + m_bEOF = true; + m_bBOF = m_aRows.empty(); + } + return bSuccess; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::wasNull( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + + if(m_aRowsIter == m_aRows.end() || !(*m_aRowsIter)[m_nColPos].is()) + return true; + + return (*m_aRowsIter)[m_nColPos]->getValue().isNull(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::refreshRow( ) +{ +} + + +void SAL_CALL ODatabaseMetaDataResultSet::cancel( ) +{ +} + +void SAL_CALL ODatabaseMetaDataResultSet::clearWarnings( ) +{ +} + +Any SAL_CALL ODatabaseMetaDataResultSet::getWarnings( ) +{ + return Any(); +} + +::cppu::IPropertyArrayHelper* ODatabaseMetaDataResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper & ODatabaseMetaDataResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +void ODatabaseMetaDataResultSet::setProceduresMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setProceduresMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setCatalogsMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setCatalogsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setSchemasMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setSchemasMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setColumnPrivilegesMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setColumnPrivilegesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setColumnsMap() +{ + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTablesMap() +{ + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setTablesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setProcedureColumnsMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setProcedureColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setPrimaryKeysMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setPrimaryKeysMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setIndexInfoMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setIndexInfoMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTablePrivilegesMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setTablePrivilegesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setCrossReferenceMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setCrossReferenceMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setVersionColumnsMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setVersionColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setBestRowIdentifierMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setBestRowIdentifierMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTypeInfoMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setTypeInfoMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setUDTsMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setUDTsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTableTypes() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setTableTypes(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setExportedKeysMap() +{ + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(); + pMetaData->setExportedKeysMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setImportedKeysMap() +{ + 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(aRowsToSet); +} +// XServiceInfo + + + OUString ODatabaseMetaDataResultSet::getImplementationName_Static( ) + { + return "org.openoffice.comp.helper.DatabaseMetaDataResultSet"; + } + + Sequence< OUString > ODatabaseMetaDataResultSet::getSupportedServiceNames_Static( ) + { + Sequence<OUString> aSNS { "com.sun.star.sdbc.ResultSet" }; + return aSNS; + } + + OUString SAL_CALL ODatabaseMetaDataResultSet::getImplementationName( ) + { + return getImplementationName_Static(); + } + + sal_Bool SAL_CALL ODatabaseMetaDataResultSet::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL ODatabaseMetaDataResultSet::getSupportedServiceNames( ) + { + return getSupportedServiceNames_Static(); + } + + namespace connectivity + { + /// @throws Exception + static Reference< XInterface > ODatabaseMetaDataResultSet_CreateInstance(const Reference< XComponentContext >& ) + { + return *(new ODatabaseMetaDataResultSet()); + } + } + + +namespace +{ + cppu::ImplementationEntry const entries[] = { + { &ODatabaseMetaDataResultSet_CreateInstance, &ODatabaseMetaDataResultSet::getImplementationName_Static, &ODatabaseMetaDataResultSet::getSupportedServiceNames_Static, + &cppu::createSingleComponentFactory, nullptr, 0 }, + { &ParameterSubstitution::create, &ParameterSubstitution::getImplementationName_Static, &ParameterSubstitution::getSupportedServiceNames_Static, + &cppu::createSingleComponentFactory, nullptr, 0 }, + { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } + }; +} + +extern "C" +{ + + +SAL_DLLPUBLIC_EXPORT void* dbtools_component_getFactory(const char* implName, void* serviceManager, void* registryKey) +{ + return cppu::component_getFactoryHelper(implName, serviceManager, registryKey, entries); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx b/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx new file mode 100644 index 000000000..561953a07 --- /dev/null +++ b/connectivity/source/commontools/FDatabaseMetaDataResultSetMetaData.cxx @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <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 000000000..2f1cabbd4 --- /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(static_cast<float>(*this)); + break; + case DataType::DOUBLE: + case DataType::REAL: + aRet = OUString::number(static_cast<double>(*this)); + break; + case DataType::DATE: + aRet = DBTypeConversion::toDateString(*this); + break; + case DataType::TIME: + aRet = DBTypeConversion::toTimeString(*this); + break; + case DataType::TIMESTAMP: + aRet = DBTypeConversion::toDateTimeString(*this); + 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(static_cast<bool>(*this))); + break; + case DataType::BOOLEAN: + aRet = OUString::boolean(static_cast<bool>(*this)); + break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + if ( m_bSigned ) + aRet = OUString::number(static_cast<sal_Int32>(*this)); + else + aRet = OUString::number(static_cast<sal_uInt32>(*this)); + break; + case DataType::BIGINT: + if ( m_bSigned ) + aRet = OUString::number(static_cast<sal_Int64>(*this)); + else + aRet = OUString::number(static_cast<sal_uInt64>(*this)); + 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(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(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(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(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(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(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(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(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(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(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(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(static_cast<double>(*this)); + 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( sal_Int64( *this ) ) ); + 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(static_cast<double>(*this)); + break; + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::REAL: + aValue = DBTypeConversion::toTime(static_cast<double>(*this)); + 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(static_cast<double>(*this)); + break; + case DataType::FLOAT: + case DataType::DOUBLE: + case DataType::REAL: + aValue = DBTypeConversion::toDateTime(static_cast<double>(*this)); + 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::makeAny(_rValueSource.getClob()); + setTypeKind(DataType::CLOB); + break; + case DataType::BLOB: + (*this) = css::uno::makeAny(_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 000000000..9adf63a93 --- /dev/null +++ b/connectivity/source/commontools/ParameterSubstitution.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 <ParameterSubstitution.hxx> +#include <connectivity/sqlparse.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <cppuhelper/supportsservice.hxx> + +namespace connectivity +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star; + + ParameterSubstitution::ParameterSubstitution(const css::uno::Reference< css::uno::XComponentContext >& _rxContext ) : m_xContext(_rxContext) + { + } + void SAL_CALL ParameterSubstitution::initialize( const uno::Sequence< uno::Any >& _aArguments ) + { + ::osl::MutexGuard aGuard(m_aMutex); + comphelper::SequenceAsHashMap aArgs(_aArguments); + uno::Reference< sdbc::XConnection > xConnection; + xConnection = aArgs.getUnpackedValueOrDefault("ActiveConnection",xConnection); + m_xConnection = xConnection; + } + + OUString ParameterSubstitution::getImplementationName_Static( ) + { + return "org.openoffice.comp.helper.ParameterSubstitution"; + } + + OUString SAL_CALL ParameterSubstitution::getImplementationName( ) + { + return getImplementationName_Static(); + } + + sal_Bool SAL_CALL ParameterSubstitution::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL ParameterSubstitution::getSupportedServiceNames( ) + { + return getSupportedServiceNames_Static(); + } + + Sequence< OUString > ParameterSubstitution::getSupportedServiceNames_Static( ) + { + return { "com.sun.star.sdb.ParameterSubstitution" }; + } + + + Reference< XInterface > ParameterSubstitution::create(const Reference< XComponentContext >& _xContext) + { + return *(new ParameterSubstitution(_xContext)); + } + + 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; + OUString sNewSql; + std::unique_ptr<OSQLParseNode> pNode = aParser.parseTree(sErrorMessage,_sText); + if(pNode) + { // special handling for parameters + OSQLParseNode::substituteParameterNames(pNode.get()); + 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 + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/RowFunctionParser.cxx b/connectivity/source/commontools/RowFunctionParser.cxx new file mode 100644 index 000000000..21f5e638a --- /dev/null +++ b/connectivity/source/commontools/RowFunctionParser.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +// Makes parser a static resource, +// we're synchronized externally. +// But watch out, the parser might have +// state not visible to this code! +#define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE + +#if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL) +#include <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> + +namespace connectivity +{ +using namespace com::sun::star; + +namespace +{ + + +// EXPRESSION NODES + + +class ConstantValueExpression : public ExpressionNode +{ + ORowSetValueDecoratorRef maValue; + +public: + + explicit ConstantValueExpression( ORowSetValueDecoratorRef const & rValue ) : + maValue( rValue ) + { + } + virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override + { + return maValue; + } + virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override + { + } +}; + + +/** ExpressionNode implementation for unary + function over two ExpressionNodes + */ +class BinaryFunctionExpression : public ExpressionNode +{ + const ExpressionFunct meFunct; + std::shared_ptr<ExpressionNode> mpFirstArg; + std::shared_ptr<ExpressionNode> mpSecondArg; + +public: + + BinaryFunctionExpression( const ExpressionFunct eFunct, const std::shared_ptr<ExpressionNode>& rFirstArg, const std::shared_ptr<ExpressionNode>& rSecondArg ) : + meFunct( eFunct ), + mpFirstArg( rFirstArg ), + mpSecondArg( rSecondArg ) + { + } + virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override + { + ORowSetValueDecoratorRef aRet; + switch(meFunct) + { + case ExpressionFunct::Equation: + aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue() ); + break; + case ExpressionFunct::And: + aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool() ); + break; + case ExpressionFunct::Or: + aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool() ); + break; + default: + break; + } + return aRet; + } + virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override + { + switch(meFunct) + { + case ExpressionFunct::Equation: + (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue(); + break; + default: + break; + } + } +}; + + +// FUNCTION PARSER + + +typedef const char* StringIteratorT; + +struct ParserContext +{ + typedef std::stack< std::shared_ptr<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( const ParserContextSharedPtr& rContext ) : + mpContext( rContext ) + { + } + void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const + { + OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 ); + mpContext->maOperandStack.push( std::make_shared<ConstantValueExpression>( new ORowSetValueDecorator( sVal ) ) ); + } +}; + +/** Generate parse-dependent-but-then-constant value + */ +class IntConstantFunctor +{ + ParserContextSharedPtr mpContext; + +public: + explicit IntConstantFunctor( const ParserContextSharedPtr& rContext ) : + mpContext( rContext ) + { + } + void operator()( sal_Int32 n ) const + { + mpContext->maOperandStack.push( std::make_shared<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, const ParserContextSharedPtr& rContext ) : + meFunct( eFunct ), + mpContext( rContext ) + { + } + + void operator()( StringIteratorT, StringIteratorT ) const + { + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.size() < 2 ) + throw ParseError( "Not enough arguments for binary operator" ); + + // retrieve arguments + std::shared_ptr<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( const std::shared_ptr<ExpressionNode>& rArg ) : + mpArg( rArg ) + { + } + virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const override + { + return _aRow[mpArg->evaluate(_aRow )->getValue().getUInt32()]; + } + virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const override + { + } +}; + +class UnaryFunctionFunctor +{ + ParserContextSharedPtr mpContext; + +public: + + explicit UnaryFunctionFunctor(const ParserContextSharedPtr& rContext) + : mpContext(rContext) + { + } + void operator()( StringIteratorT, StringIteratorT ) const + { + + ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack ); + + if( rNodeStack.empty() ) + throw ParseError( "Not enough arguments for unary operator" ); + + // retrieve arguments + std::shared_ptr<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( const ParserContextSharedPtr& rParserContext ) : + mpParserContext( rParserContext ) + { + } + + template< typename ScannerT > class definition + { + public: + // grammar definition + explicit definition( const ExpressionGrammar& self ) + { + using ::boost::spirit::classic::space_p; + using ::boost::spirit::classic::range_p; + using ::boost::spirit::classic::lexeme_d; + using ::boost::spirit::classic::ch_p; + using ::boost::spirit::classic::int_p; + using ::boost::spirit::classic::as_lower_d; + using ::boost::spirit::classic::strlit; + using ::boost::spirit::classic::inhibit_case; + + + typedef inhibit_case<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 000000000..a97faeeb8 --- /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,"*" ,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; + 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 000000000..134aa5960 --- /dev/null +++ b/connectivity/source/commontools/TConnection.cxx @@ -0,0 +1,89 @@ +/* -*- 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 <cppuhelper/typeprovider.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 (isUnoTunnelId<OMetaConnection>(rId)) + ? reinterpret_cast< sal_Int64 >( this ) + : sal_Int64(0); +} + +Sequence< sal_Int8 > OMetaConnection::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +::dbtools::OPropertyMap& OMetaConnection::getPropMap() +{ + static ::dbtools::OPropertyMap s_aPropertyNameMap; + return s_aPropertyNameMap; +} + +void OMetaConnection::throwGenericSQLException(const char* pErrorResourceId, const Reference< XInterface>& _xContext ) +{ + OUString sErrorMessage; + if (pErrorResourceId) + sErrorMessage = m_aResources.getResourceString(pErrorResourceId); + Reference< XInterface> xContext = _xContext; + if ( !xContext.is() ) + xContext = *this; + ::dbtools::throwGenericSQLException( sErrorMessage, xContext); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TDatabaseMetaDataBase.cxx b/connectivity/source/commontools/TDatabaseMetaDataBase.cxx new file mode 100644 index 000000000..e58232780 --- /dev/null +++ b/connectivity/source/commontools/TDatabaseMetaDataBase.cxx @@ -0,0 +1,326 @@ +/* -*- 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 <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 (sal_Int32 i = 1; i <= sal_Int32(SAL_N_ELEMENTS(pTypes)); ++i,++pType) + { + ORowSetValue aValue; + aValue.fill(i,*pType,xRow); + aRow.push_back(new ORowSetValueDecorator(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; + } + } + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo); + Reference< XResultSet > xRet = pResult; + pResult->setRows(m_aTypeInfoRows); + return xRet; +} + +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 000000000..f7f891308 --- /dev/null +++ b/connectivity/source/commontools/TIndex.cxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <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 000000000..bbb5ca706 --- /dev/null +++ b/connectivity/source/commontools/TIndexColumns.cxx @@ -0,0 +1,115 @@ +/* -*- 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)); + + OIndexColumn* pRet = new OIndexColumn(bAsc, + _rName, + aTypeName, + aColumnDef, + nNull, + nSize, + nDec, + nDataType, + true, + aCatalog, aSchema, aTable); + xRet = pRet; + break; + } + } + } + + return xRet; +} + +Reference< XPropertySet > OIndexColumns::createDescriptor() +{ + return new OIndexColumn(true); +} + +void OIndexColumns::impl_refresh() +{ + m_pIndex->refreshColumns(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TIndexes.cxx b/connectivity/source/commontools/TIndexes.cxx new file mode 100644 index 000000000..f5cff00ec --- /dev/null +++ b/connectivity/source/commontools/TIndexes.cxx @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <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&) + { + } + OIndexHelper* pRet = new OIndexHelper(m_pTable,aName,aQualifier,bUnique, + bPrimarKeyIndex, + nClustered == IndexType::CLUSTERED); + xRet = pRet; + break; + } + } + } + + return xRet; +} + +void OIndexesHelper::impl_refresh() +{ + m_pTable->refreshIndexes(); +} + +Reference< XPropertySet > OIndexesHelper::createDescriptor() +{ + return new OIndexHelper(m_pTable); +} + +// XAppend +sdbcx::ObjectType OIndexesHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + Reference< XConnection> xConnection = m_pTable->getConnection(); + if ( !xConnection.is() ) + return nullptr; + if ( m_pTable->isNew() ) + return cloneDescriptor( descriptor ); + + if ( m_pTable->getIndexService().is() ) + { + m_pTable->getIndexService()->addIndex(m_pTable,descriptor); + } + else + { + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + OUStringBuffer aSql( "CREATE " ); + OUString aQuote = m_pTable->getMetaData()->getIdentifierQuoteString( ); + + if(comphelper::getBOOL(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISUNIQUE)))) + aSql.append("UNIQUE "); + aSql.append("INDEX "); + + + OUString aCatalog,aSchema,aTable; + dbtools::qualifiedNameComponents(m_pTable->getMetaData(),m_pTable->getName(),aCatalog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation); + + OUString aComposedName = dbtools::composeTableName(m_pTable->getMetaData(),aCatalog,aSchema,aTable, true, ::dbtools::EComposeRule::InIndexDefinitions); + if (!_rForName.isEmpty() ) + { + aSql.append( ::dbtools::quoteName( aQuote, _rForName ) ); + aSql.append(" ON "); + aSql.append(aComposedName); + aSql.append(" ( "); + + Reference<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("."); + aSql.append(::dbtools::quoteName( aQuote,comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))))); + } + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + if ( xStmt.is() ) + { + OUString sSql = aSql.makeStringAndClear(); + xStmt->execute(sSql); + ::comphelper::disposeComponent(xStmt); + } + } + + return createObject( _rForName ); +} + +// XDrop +void OIndexesHelper::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + Reference< XConnection> xConnection = m_pTable->getConnection(); + if( !(xConnection.is() && !m_pTable->isNew())) + return; + + if ( m_pTable->getIndexService().is() ) + { + m_pTable->getIndexService()->dropIndex(m_pTable,_sElementName); + } + else + { + OUString aName,aSchema; + sal_Int32 nLen = _sElementName.indexOf('.'); + if(nLen != -1) + aSchema = _sElementName.copy(0,nLen); + aName = _sElementName.copy(nLen+1); + + OUString aSql( "DROP INDEX " ); + + OUString aComposedName = dbtools::composeTableName( m_pTable->getMetaData(), m_pTable, ::dbtools::EComposeRule::InIndexDefinitions, true ); + OUString sIndexName = dbtools::composeTableName( m_pTable->getMetaData(), OUString(), aSchema, aName, true, ::dbtools::EComposeRule::InIndexDefinitions ); + + aSql += sIndexName + " ON " + aComposedName; + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TKey.cxx b/connectivity/source/commontools/TKey.cxx new file mode 100644 index 000000000..1341291ab --- /dev/null +++ b/connectivity/source/commontools/TKey.cxx @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <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 000000000..acbfc54bf --- /dev/null +++ b/connectivity/source/commontools/TKeyColumns.cxx @@ -0,0 +1,133 @@ +/* -*- 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 + } + + OKeyColumn* pRet = new OKeyColumn(aRefColumnName, + _rName, + aTypeName, + sColumnDef, + nNull, + nSize, + nDec, + nDataType, + isCaseSensitive(), + aCatalog, + aSchema, + aTable); + xRet = pRet; + } + } + } + + return xRet; +} + +Reference< XPropertySet > OKeyColumnsHelper::createDescriptor() +{ + return new OKeyColumn(isCaseSensitive()); +} + +void OKeyColumnsHelper::impl_refresh() +{ + m_pKey->refreshColumns(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TKeys.cxx b/connectivity/source/commontools/TKeys.cxx new file mode 100644 index 000000000..742a18320 --- /dev/null +++ b/connectivity/source/commontools/TKeys.cxx @@ -0,0 +1,311 @@ +/* -*- 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()) + { + OTableKeyHelper* pRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName)); + xRet = pRet; + } + + if(!xRet.is()) // we have a primary key with a system name + { + OTableKeyHelper* pRet = new OTableKeyHelper(m_pTable,_rName,m_pTable->getKeyProperties(_rName)); + xRet = pRet; + } + + return xRet; +} + +void OKeysHelper::impl_refresh() +{ + m_pTable->refreshKeys(); +} + +Reference< XPropertySet > OKeysHelper::createDescriptor() +{ + return new OTableKeyHelper(m_pTable); +} + +/** returns the keyrule string for the primary key +*/ +static OUString getKeyRuleString(bool _bUpdate,sal_Int32 _nKeyRule) +{ + const char* pKeyRule = nullptr; + switch ( _nKeyRule ) + { + case KeyRule::CASCADE: + pKeyRule = _bUpdate ? " ON UPDATE CASCADE " : " ON DELETE CASCADE "; + break; + case KeyRule::RESTRICT: + pKeyRule = _bUpdate ? " ON UPDATE RESTRICT " : " ON DELETE RESTRICT "; + break; + case KeyRule::SET_NULL: + pKeyRule = _bUpdate ? " ON UPDATE SET NULL " : " ON DELETE SET NULL "; + break; + case KeyRule::SET_DEFAULT: + pKeyRule = _bUpdate ? " ON UPDATE SET DEFAULT " : " ON DELETE SET DEFAULT "; + break; + default: + ; + } + OUString sRet; + if ( pKeyRule ) + sRet = OUString::createFromAscii(pKeyRule); + return sRet; +} + +void OKeysHelper::cloneDescriptorColumns( const sdbcx::ObjectType& _rSourceDescriptor, const sdbcx::ObjectType& _rDestDescriptor ) +{ + Reference< XColumnsSupplier > xColSupp( _rSourceDescriptor, UNO_QUERY_THROW ); + Reference< XIndexAccess > xSourceCols( xColSupp->getColumns(), UNO_QUERY_THROW ); + + xColSupp.set( _rDestDescriptor, UNO_QUERY_THROW ); + Reference< XAppend > xDestAppend( xColSupp->getColumns(), UNO_QUERY_THROW ); + + sal_Int32 nCount = xSourceCols->getCount(); + for ( sal_Int32 i=0; i< nCount; ++i ) + { + Reference< XPropertySet > xColProp( xSourceCols->getByIndex(i), UNO_QUERY ); + xDestAppend->appendByDescriptor( xColProp ); + } +} + +// XAppend +sdbcx::ObjectType OKeysHelper::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + Reference< XConnection> xConnection = m_pTable->getConnection(); + if ( !xConnection.is() ) + return nullptr; + if ( m_pTable->isNew() ) + { + Reference< XPropertySet > xNewDescriptor( cloneDescriptor( descriptor ) ); + cloneDescriptorColumns( descriptor, xNewDescriptor ); + return xNewDescriptor; + } + + const ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + sal_Int32 nKeyType = getINT32(descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE))); + sal_Int32 nUpdateRule = 0, nDeleteRule = 0; + OUString sReferencedName; + + if ( nKeyType == KeyType::FOREIGN ) + { + descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_REFERENCEDTABLE)) >>= sReferencedName; + descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_UPDATERULE)) >>= nUpdateRule; + descriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_DELETERULE)) >>= nDeleteRule; + } + + if ( m_pTable->getKeyService().is() ) + { + m_pTable->getKeyService()->addKey(m_pTable,descriptor); + } + else + { + // if we're here, we belong to a table which is not new, i.e. already exists in the database. + // In this case, really append the new index. + OUStringBuffer aSql; + aSql.append("ALTER TABLE "); + OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString( ); + + aSql.append(composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable, ::dbtools::EComposeRule::InTableDefinitions, true )); + aSql.append(" ADD "); + + if ( nKeyType == KeyType::PRIMARY ) + { + aSql.append(" PRIMARY KEY ("); + } + else if ( nKeyType == KeyType::FOREIGN ) + { + aSql.append(" FOREIGN KEY ("); + } + else + throw SQLException(); + + Reference<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 "); + aSql.append(::dbtools::quoteTableName(m_pTable->getConnection()->getMetaData(),sReferencedName,::dbtools::EComposeRule::InTableDefinitions)); + aSql.append(" ("); + + 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(")"); + aSql.append(getKeyRuleString(true ,nUpdateRule)); + aSql.append(getKeyRuleString(false ,nDeleteRule)); + } + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + xStmt->execute(aSql.makeStringAndClear()); + } + // find the name which the database gave the new key + OUString sNewName( _rForName ); + try + { + OUString aSchema,aTable; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= aSchema; + m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= aTable; + Reference< XResultSet > xResult; + sal_Int32 nColumn = 12; + if ( nKeyType == KeyType::FOREIGN ) + xResult = m_pTable->getMetaData()->getImportedKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) + ,aSchema + ,aTable); + else + { + xResult = m_pTable->getMetaData()->getPrimaryKeys( m_pTable->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) + ,aSchema + ,aTable); + nColumn = 6; + } + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + { + OUString sName = xRow->getString(nColumn); + if ( !m_pElements->exists(sName) ) // this name wasn't inserted yet so it must be the new one + { + descriptor->setPropertyValue( rPropMap.getNameByIndex( PROPERTY_ID_NAME ), makeAny( 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; + aSql.append("ALTER TABLE "); + + aSql.append( composeTableName( m_pTable->getConnection()->getMetaData(), m_pTable,::dbtools::EComposeRule::InTableDefinitions, true )); + + sal_Int32 nKeyType = KeyType::PRIMARY; + if ( xKey.is() ) + { + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + xKey->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) >>= nKeyType; + } + if ( KeyType::PRIMARY == nKeyType ) + { + aSql.append(" DROP PRIMARY KEY"); + } + else + { + aSql.append(getDropForeignKey()); + const OUString aQuote = m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString(); + aSql.append( ::dbtools::quoteName( aQuote,_sElementName) ); + } + + Reference< XStatement > xStmt = m_pTable->getConnection()->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql.makeStringAndClear()); + ::comphelper::disposeComponent(xStmt); + } + } +} + +} // namespace connectivity + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TPrivilegesResultSet.cxx b/connectivity/source/commontools/TPrivilegesResultSet.cxx new file mode 100644 index 000000000..de255d3cb --- /dev/null +++ b/connectivity/source/commontools/TPrivilegesResultSet.cxx @@ -0,0 +1,143 @@ +/* -*- 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; + Sequence< OUString > sTableTypes(3); + // we want all catalogues, all schemas, all tables + sTableTypes[0] = "VIEW"; + sTableTypes[1] = "TABLE"; + sTableTypes[2] = "%"; // 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(aRows); + } + osl_atomic_decrement( &m_refCount ); +} + +const ORowSetValue& OResultSetPrivileges::getValue(sal_Int32 columnIndex) +{ + switch(columnIndex) + { + case 1: + case 2: + case 3: + if ( m_xRow.is() && m_bResetValues ) + { + (*m_aRowsIter)[1] = new ORowSetValueDecorator(m_xRow->getString(1)); + if ( m_xRow->wasNull() ) + (*m_aRowsIter)[1]->setNull(); + (*m_aRowsIter)[2] = new ORowSetValueDecorator(m_xRow->getString(2)); + if ( m_xRow->wasNull() ) + (*m_aRowsIter)[2]->setNull(); + (*m_aRowsIter)[3] = new ORowSetValueDecorator(m_xRow->getString(3)); + if ( m_xRow->wasNull() ) + (*m_aRowsIter)[3]->setNull(); + + m_bResetValues = false; + } + } + return ODatabaseMetaDataResultSet::getValue(columnIndex); +} + +void SAL_CALL OResultSetPrivileges::disposing() +{ + ODatabaseMetaDataResultSet::disposing(); + m_xTables.clear(); + m_xRow.clear(); +} + +sal_Bool SAL_CALL OResultSetPrivileges::next( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + bool bReturn = false; + if ( m_xTables.is() ) + { + if ( m_bBOF ) + { + m_bResetValues = true; + if ( !m_xTables->next() ) + return false; + } + + bReturn = ODatabaseMetaDataResultSet::next(); + if ( !bReturn ) + { + m_bBOF = false; + m_bResetValues = bReturn = m_xTables->next(); + } + } + return bReturn; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/TSkipDeletedSet.cxx b/connectivity/source/commontools/TSkipDeletedSet.cxx new file mode 100644 index 000000000..d3ae392f7 --- /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,nLastBookmark = 1; + 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 + { + 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 000000000..6b94216a3 --- /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( const std::vector<OKeyType>& _aKeyType, + const std::vector<TAscendingOrder>& _aAscending) + :m_aKeyType(_aKeyType) + ,m_aAscending(_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 000000000..03724d669 --- /dev/null +++ b/connectivity/source/commontools/TTableHelper.cxx @@ -0,0 +1,605 @@ +/* -*- 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.get()); + 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 = 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.get()); + 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 = createKeys(aNames); + } // if(!isNew()) + else if (!m_xKeys ) + m_xKeys = 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 = 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; +} + +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 000000000..d0198df5f --- /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 <tools/diagnose_ex.h> + + +namespace dbtools +{ + + + using namespace css::uno; + using namespace css::beans; + using namespace css::sdbc; + using namespace css::lang; + + static const char ACTIVE_CONNECTION_PROPERTY_NAME[] = "ActiveConnection"; + + OAutoConnectionDisposer::OAutoConnectionDisposer(const Reference< XRowSet >& _rxRowSet, const Reference< XConnection >& _rxConnection) + :m_xRowSet( _rxRowSet ) + ,m_bRSListening( false ) + ,m_bPropertyListening( false ) + { + Reference< XPropertySet > xProps(_rxRowSet, UNO_QUERY); + OSL_ENSURE(xProps.is(), "OAutoConnectionDisposer::OAutoConnectionDisposer: invalid rowset (no XPropertySet)!"); + + if (!xProps.is()) + return; + + try + { + xProps->setPropertyValue( ACTIVE_CONNECTION_PROPERTY_NAME, makeAny( _rxConnection ) ); + m_xOriginalConnection = _rxConnection; + startPropertyListening( xProps ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::OAutoConnectionDisposer" ); + } + } + + + void OAutoConnectionDisposer::startPropertyListening( const Reference< XPropertySet >& _rxRowSet ) + { + try + { + _rxRowSet->addPropertyChangeListener( ACTIVE_CONNECTION_PROPERTY_NAME, this ); + m_bPropertyListening = true; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::startPropertyListening" ); + } + } + + + void OAutoConnectionDisposer::stopPropertyListening( const Reference< XPropertySet >& _rxEventSource ) + { + // prevent deletion of ourself while we're herein + Reference< XInterface > xKeepAlive(static_cast< XWeak* >(this)); + + try + { // remove ourself as property change listener + OSL_ENSURE( _rxEventSource.is(), "OAutoConnectionDisposer::stopPropertyListening: invalid event source (no XPropertySet)!" ); + if ( _rxEventSource.is() ) + { + _rxEventSource->removePropertyChangeListener( ACTIVE_CONNECTION_PROPERTY_NAME, this ); + m_bPropertyListening = false; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::stopPropertyListening" ); + } + } + + + void OAutoConnectionDisposer::startRowSetListening() + { + OSL_ENSURE( !m_bRSListening, "OAutoConnectionDisposer::startRowSetListening: already listening!" ); + try + { + if ( !m_bRSListening ) + m_xRowSet->addRowSetListener( this ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::startRowSetListening" ); + } + m_bRSListening = true; + } + + + void OAutoConnectionDisposer::stopRowSetListening() + { + OSL_ENSURE( m_bRSListening, "OAutoConnectionDisposer::stopRowSetListening: not listening!" ); + try + { + m_xRowSet->removeRowSetListener( this ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OAutoConnectionDisposer::stopRowSetListening" ); + } + m_bRSListening = false; + } + + + void SAL_CALL OAutoConnectionDisposer::propertyChange( const PropertyChangeEvent& _rEvent ) + { + if ( _rEvent.PropertyName != ACTIVE_CONNECTION_PROPERTY_NAME ) + return; + +// somebody set a new ActiveConnection + + Reference< XConnection > xNewConnection; + _rEvent.NewValue >>= xNewConnection; + + if ( isRowSetListening() ) + { + // we're listening at the row set, this means that the row set does not have our + // m_xOriginalConnection as active connection anymore + // So there are two possibilities + // a. somebody sets a new connection which is not our original one + // b. somebody sets a new connection, which is exactly the original one + // a. we're not interested in a, but in b: In this case, we simply need to move to the state + // we had originally: listen for property changes, do not listen for row set changes, and + // do not dispose the connection until the row set does not need it anymore + if ( xNewConnection.get() == m_xOriginalConnection.get() ) + { + stopRowSetListening(); + } + } + else + { + // start listening at the row set. We're allowed to dispose the old connection as soon + // as the RowSet changed + + // Unfortunately, the our database form implementations sometimes fire the change of their + // ActiveConnection twice. This is an error in forms/source/component/DatabaseForm.cxx, but + // changing this would require incompatible changes we can't do for a while. + // So for the moment, we have to live with it here. + // + // The only scenario where this doubled notification causes problems is when the connection + // of the form is reset to the one we're responsible for (m_xOriginalConnection), so we + // check this here. + // + // Yes, this is a HACK :( + if ( xNewConnection.get() != m_xOriginalConnection.get() ) + { +#if OSL_DEBUG_LEVEL > 0 + Reference< XConnection > xOldConnection; + _rEvent.OldValue >>= xOldConnection; + OSL_ENSURE( xOldConnection.get() == m_xOriginalConnection.get(), "OAutoConnectionDisposer::propertyChange: unexpected (original) property value!" ); +#endif + startRowSetListening(); + } + } + } + + + void SAL_CALL OAutoConnectionDisposer::disposing( const EventObject& _rSource ) + { + // the rowset is being disposed, and nobody has set a new ActiveConnection in the meantime + if ( isRowSetListening() ) + stopRowSetListening(); + + clearConnection(); + + if ( m_bPropertyListening ) + stopPropertyListening( Reference< XPropertySet >( _rSource.Source, UNO_QUERY ) ); + } + + void OAutoConnectionDisposer::clearConnection() + { + try + { + // dispose the old connection + Reference< XComponent > xComp(m_xOriginalConnection, UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + m_xOriginalConnection.clear(); + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("connectivity.commontools", "OAutoConnectionDisposer::clearConnection"); + } + } + + void SAL_CALL OAutoConnectionDisposer::cursorMoved( const css::lang::EventObject& /*event*/ ) + { + } + + void SAL_CALL OAutoConnectionDisposer::rowChanged( const css::lang::EventObject& /*event*/ ) + { + } + + void SAL_CALL OAutoConnectionDisposer::rowSetChanged( const css::lang::EventObject& /*event*/ ) + { + stopRowSetListening(); + clearConnection(); + + } + + +} // namespace dbtools + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/dbcharset.cxx b/connectivity/source/commontools/dbcharset.cxx new file mode 100644 index 000000000..ebe45c028 --- /dev/null +++ b/connectivity/source/commontools/dbcharset.cxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <connectivity/dbcharset.hxx> +#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(const OUString& _rIanaName) const + { + ensureConstructed( ); + + rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW; + if ( !_rIanaName.isEmpty() ) + { + // byte string conversion + OString sMimeByteString( _rIanaName.getStr(), _rIanaName.getLength(), RTL_TEXTENCODING_ASCII_US ); + // look up + eEncoding = rtl_getTextEncodingFromMimeCharset( sMimeByteString.getStr() ); + + if ( RTL_TEXTENCODING_DONTKNOW == eEncoding ) + { // if we're here, the name is not empty, but unknown -> this is an invalid name + return end(); + } + } + + return find( eEncoding ); + } + + + OCharsetMap::CharsetIterator OCharsetMap::end() const + { + ensureConstructed( ); + + return CharsetIterator( this, m_aEncodings.end() ); + } + + + CharsetIteratorDerefHelper::CharsetIteratorDerefHelper( const CharsetIteratorDerefHelper& _rSource ) + :m_eEncoding( _rSource.m_eEncoding ) + ,m_aIanaName( _rSource.m_aIanaName ) + { + } + + + CharsetIteratorDerefHelper:: CharsetIteratorDerefHelper(const rtl_TextEncoding _eEncoding, const OUString& _rIanaName ) + :m_eEncoding( _eEncoding ) + ,m_aIanaName( _rIanaName ) + { + } + + OCharsetMap::CharsetIterator::CharsetIterator(const OCharsetMap* _pContainer, OCharsetMap::TextEncBag::const_iterator const & _aPos ) + :m_pContainer( _pContainer ) + ,m_aPos( _aPos ) + { + OSL_ENSURE( m_pContainer, "OCharsetMap::CharsetIterator::CharsetIterator : invalid container!" ); + } + + CharsetIteratorDerefHelper OCharsetMap::CharsetIterator::operator*() const + { + OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.end(), "OCharsetMap::CharsetIterator::operator*: invalid position!"); + + rtl_TextEncoding eEncoding = *m_aPos; + OUString sIanaName; + + if ( RTL_TEXTENCODING_DONTKNOW != eEncoding ) + { // it's not the virtual "system charset" + const char* pIanaName = rtl_getMimeCharsetFromTextEncoding( eEncoding ); + OSL_ENSURE( pIanaName, "OCharsetMap::CharsetIterator: invalid mime name!" ); + if ( pIanaName ) + sIanaName = OUString::createFromAscii( pIanaName ); + } + return CharsetIteratorDerefHelper( eEncoding, sIanaName ); + } + + + const OCharsetMap::CharsetIterator& OCharsetMap::CharsetIterator::operator++() + { + OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.end(), "OCharsetMap::CharsetIterator::operator++ : invalid position!" ); + if ( m_aPos != m_pContainer->m_aEncodings.end()) + ++m_aPos; + return *this; + } + + + const OCharsetMap::CharsetIterator& OCharsetMap::CharsetIterator::operator--() + { + OSL_ENSURE( m_aPos != m_pContainer->m_aEncodings.begin(), "OCharsetMap::CharsetIterator::operator-- : invalid position!" ); + if ( m_aPos != m_pContainer->m_aEncodings.begin() ) + --m_aPos; + return *this; + } + + + bool operator==(const OCharsetMap::CharsetIterator& lhs, const OCharsetMap::CharsetIterator& rhs) + { + return ( lhs.m_pContainer == rhs.m_pContainer ) && ( lhs.m_aPos == rhs.m_aPos ); + } + + +} // namespace dbtools + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/dbconversion.cxx b/connectivity/source/commontools/dbconversion.cxx new file mode 100644 index 000000000..3dd42e9ca --- /dev/null +++ b/connectivity/source/commontools/dbconversion.cxx @@ -0,0 +1,461 @@ +/* -*- 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 <osl/diagnose.h> +#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/ustrbuf.hxx> +#include <rtl/math.hxx> +#include <unotools/datetime.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().c_str()); + } + + OUString DBTypeConversion::toTimeStringS(const css::util::Time& rTime) + { + std::ostringstream ostr; + using std::setw; + ostr.fill('0'); + ostr << setw(2) << rTime.Hours << ":" + << setw(2) << rTime.Minutes << ":" + << setw(2) << rTime.Seconds; + return OUString::createFromAscii(ostr.str().c_str()); + } + + OUString DBTypeConversion::toTimeString(const css::util::Time& rTime) + { + std::ostringstream ostr; + using std::setw; + ostr.fill('0'); + ostr << setw(2) << rTime.Hours << ":" + << setw(2) << rTime.Minutes << ":" + << setw(2) << rTime.Seconds << "." + << setw(9) << rTime.NanoSeconds; + return OUString::createFromAscii(ostr.str().c_str()); + } + + OUString DBTypeConversion::toDateTimeString(const css::util::DateTime& _rDateTime) + { + css::util::Date aDate(_rDateTime.Day,_rDateTime.Month,_rDateTime.Year); + OUStringBuffer aTemp(toDateString(aDate)); + aTemp.append(" "); + css::util::Time const aTime(_rDateTime.NanoSeconds, _rDateTime.Seconds, + _rDateTime.Minutes, _rDateTime.Hours, _rDateTime.IsUTC); + aTemp.append( toTimeString(aTime) ); + return aTemp.makeStringAndClear(); + } + + 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 const sal_Int32 aDaysInMonth[12] = { 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 }; + + + static bool implIsLeapYear(sal_Int32 _nYear) + { + return ( ((_nYear % 4) == 0) + && ((_nYear % 100) != 0) + ) + + || ((_nYear % 400) == 0) + ; + } + + + static sal_Int32 implDaysInMonth(sal_Int32 _nMonth, sal_Int32 _nYear) + { + OSL_ENSURE(_nMonth > 0 && _nMonth < 13,"Month as invalid value!"); + if (_nMonth != 2) + return aDaysInMonth[_nMonth-1]; + else + { + if (implIsLeapYear(_nYear)) + return aDaysInMonth[_nMonth-1] + 1; + else + return aDaysInMonth[_nMonth-1]; + } + } + + + static sal_Int32 implRelativeToAbsoluteNull(const css::util::Date& _rDate) + { + sal_Int32 nDays = 0; + + // ripped this code from the implementation of tools::Date + sal_Int32 nNormalizedYear = _rDate.Year - 1; + nDays = nNormalizedYear * 365; + // leap years + nDays += (nNormalizedYear / 4) - (nNormalizedYear / 100) + (nNormalizedYear / 400); + + for (sal_Int32 i = 1; i < _rDate.Month; ++i) + nDays += implDaysInMonth(i, _rDate.Year); + + nDays += _rDate.Day; + return nDays; + } + + static void implBuildFromRelative( const sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_Int16& rYear) + { + sal_Int32 nTempDays; + sal_Int32 i = 0; + bool bCalc; + + do + { + nTempDays = nDays; + rYear = static_cast<sal_uInt16>((nTempDays / 365) - i); + nTempDays -= (rYear-1) * 365; + nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400); + bCalc = false; + if ( nTempDays < 1 ) + { + i++; + bCalc = true; + } + else + { + if ( nTempDays > 365 ) + { + if ( (nTempDays != 366) || !implIsLeapYear( rYear ) ) + { + i--; + bCalc = true; + } + } + } + } + while ( bCalc ); + + rMonth = 1; + while ( nTempDays > implDaysInMonth( rMonth, rYear ) ) + { + nTempDays -= implDaysInMonth( rMonth, rYear ); + rMonth++; + } + rDay = static_cast<sal_uInt16>(nTempDays); + } + + sal_Int32 DBTypeConversion::toDays(const css::util::Date& _rVal, const css::util::Date& _rNullDate) + { + return implRelativeToAbsoluteNull(_rVal) - implRelativeToAbsoluteNull(_rNullDate); + } + + + double DBTypeConversion::toDouble(const css::util::Date& rVal, const css::util::Date& _rNullDate) + { + return static_cast<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_Int32 nTempDays = implRelativeToAbsoluteNull( _rDate ); + + nTempDays += nDays; + if ( nTempDays > maxDays ) + { + _rDate.Day = 31; + _rDate.Month = 12; + _rDate.Year = 9999; + } + // TODO: can we replace that check by minDays? Would allow dates BCE + // implBuildFromRelative probably needs to be updated for the "no year 0" question + else if ( nTempDays <= 0 ) + { + _rDate.Day = 1; + _rDate.Month = 1; + _rDate.Year = 1; + } + else + implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year ); + } + + static void subDays(const sal_Int32 nDays, css::util::Date& _rDate ) + { + sal_Int32 nTempDays = implRelativeToAbsoluteNull( _rDate ); + + nTempDays -= nDays; + if ( nTempDays > maxDays ) + { + _rDate.Day = 31; + _rDate.Month = 12; + _rDate.Year = 9999; + } + // TODO: can we replace that check by minDays? Would allow dates BCE + // implBuildFromRelative probably needs to be updated for the "no year 0" question + else if ( nTempDays <= 0 ) + { + _rDate.Day = 1; + _rDate.Month = 1; + _rDate.Year = 1; + } + else + implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year ); + } + + css::util::Date DBTypeConversion::toDate(const double dVal, const css::util::Date& _rNullDate) + { + css::util::Date aRet = _rNullDate; + + if (dVal >= 0) + addDays(static_cast<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 sal_Int32 nDays = static_cast<sal_Int32>(dVal); + sal_Int64 nNS; + { + double fSeconds((dVal - static_cast<double>(nDays)) * (fNanoSecondsPerDay / nanoSecInSec)); + fSeconds = ::rtl::math::round( fSeconds, nDigits ); + 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::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); + + css::util::DateTime aRet; + + 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(const OUString& _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>(_sSQLString.getToken(0,sDateSep,nIndex).toInt32()); + if(nIndex != -1) + { + nMonth = static_cast<sal_uInt16>(_sSQLString.getToken(0,sDateSep,nIndex).toInt32()); + if(nIndex != -1) + nDay = static_cast<sal_uInt16>(_sSQLString.getToken(0,sDateSep,nIndex).toInt32()); + } + + 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.copy( 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(const OUString& _sSQLString) + { + css::util::Time aTime; + ::utl::ISO8601parseTime(_sSQLString, aTime); + return aTime; + } + + +} // namespace dbtools + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/commontools/dbexception.cxx b/connectivity/source/commontools/dbexception.cxx new file mode 100644 index 000000000..f15237d82 --- /dev/null +++ b/connectivity/source/commontools/dbexception.cxx @@ -0,0 +1,481 @@ +/* -*- 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> + +namespace dbtools +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::sdbc; + using namespace ::comphelper; + using namespace ::connectivity; + +SQLExceptionInfo::SQLExceptionInfo() + :m_eType(TYPE::Undefined) +{ +} + + +SQLExceptionInfo::SQLExceptionInfo(const css::sdbc::SQLException& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); +} + + +SQLExceptionInfo::SQLExceptionInfo(const css::sdbc::SQLWarning& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); +} + + +SQLExceptionInfo::SQLExceptionInfo(const css::sdb::SQLContext& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); +} + + +SQLExceptionInfo::SQLExceptionInfo( const OUString& _rSimpleErrorMessage ) +{ + SQLException aError; + aError.Message = _rSimpleErrorMessage; + m_aContent <<= aError; + implDetermineType(); +} + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdbc::SQLException& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdbc::SQLWarning& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdb::SQLContext& _rError) +{ + m_aContent <<= _rError; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::sdb::SQLErrorEvent& _rErrorEvent) +{ + m_aContent = _rErrorEvent.Reason; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo& SQLExceptionInfo::operator=(const css::uno::Any& _rCaughtSQLException) +{ + m_aContent = _rCaughtSQLException; + implDetermineType(); + return *this; +} + + +SQLExceptionInfo::SQLExceptionInfo(const css::uno::Any& _rError) +{ + const css::uno::Type& aSQLExceptionType = cppu::UnoType<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; + aException.Message = _rErrorMessage; + aException.ErrorCode = 0; + aException.SQLState = "S1000"; + aException.NextException = m_aContent; + m_aContent <<= aException; + + m_eType = TYPE::SQLException; +} + + +void SQLExceptionInfo::append( TYPE _eType, const OUString& _rErrorMessage, const OUString& _rSQLState, const sal_Int32 _nErrorCode ) +{ + // create the to-be-appended exception + Any aAppend; + switch ( _eType ) + { + case TYPE::SQLException: aAppend <<= SQLException(); break; + case TYPE::SQLWarning: aAppend <<= SQLWarning(); break; + case TYPE::SQLContext: aAppend <<= SQLContext(); break; + default: + OSL_FAIL( "SQLExceptionInfo::append: invalid exception type: this will crash!" ); + break; + } + + SQLException& pAppendException = const_cast<SQLException &>(*o3tl::forceAccess<SQLException>(aAppend)); + pAppendException.Message = _rErrorMessage; + pAppendException.SQLState = _rSQLState; + pAppendException.ErrorCode = _nErrorCode; + + // find the end of the current chain + Any* pChainIterator = &m_aContent; + SQLException* pLastException = nullptr; + const Type& aSQLExceptionType( cppu::UnoType<SQLException>::get() ); + while ( pChainIterator ) + { + if ( !pChainIterator->hasValue() ) + break; + + if ( !isAssignableFrom( aSQLExceptionType, pChainIterator->getValueType() ) ) + break; + + pLastException = const_cast< SQLException* >( o3tl::doAccess<SQLException>( *pChainIterator ) ); + pChainIterator = &pLastException->NextException; + } + + // 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 000000000..f8afdcda6 --- /dev/null +++ b/connectivity/source/commontools/dbmetadata.cxx @@ -0,0 +1,448 @@ +/* -*- 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 <tools/diagnose_ex.h> +#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() + :xConnection() + ,xConnectionMetaData() + ,aDriverConfig( ::comphelper::getProcessComponentContext() ) + ,sCachedIdentifierQuoteString() + ,sCachedCatalogSeparator() + { + } + }; + + + 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 char* _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 char* _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( OUString::createFromAscii( _asciiName ) ); + } + else + { + Reference< XDatabaseMetaData2 > xExtendedMetaData( _metaData.xConnectionMetaData, UNO_QUERY_THROW ); + ::comphelper::NamedValueCollection aSettings( xExtendedMetaData->getConnectionInfo() ); + _out_setting = aSettings.get( _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 000000000..419cd26e7 --- /dev/null +++ b/connectivity/source/commontools/dbtools.cxx @@ -0,0 +1,2086 @@ +/* -*- 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/task/XInteractionRequest.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 <tools/diagnose_ex.h> +#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(1); + NamedValue aParam( "ParentWindow", makeAny(_rxParent) ); + aArgs[0] <<= aParam; + 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(1); + NamedValue aParam( "ParentWindow", makeAny(Reference<XWindow>()) ); + aArgs[0] <<= aParam; + 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&) + { + OSL_FAIL("::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", makeAny( 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) + + const OUString sUserProp( "User" ); + OUString sDataSourceName; + xRowSetProps->getPropertyValue("DataSourceName") >>= sDataSourceName; + OUString sURL; + xRowSetProps->getPropertyValue("URL") >>= sURL; + + Reference< XConnection > xPureConnection; + if (!sDataSourceName.isEmpty()) + { // the row set's data source property is set + // -> try to connect, get user and pwd setting for that + OUString sUser, sPwd; + + if (hasProperty(sUserProp, xRowSetProps)) + xRowSetProps->getPropertyValue(sUserProp) >>= sUser; + if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps)) + xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd; + + xPureConnection = getConnection_allowException( sDataSourceName, sUser, sPwd, _rxContext, _rxParent ); + } + else if (!sURL.isEmpty()) + { // the row set has no data source, but a connection url set + // -> try to connection with that url + Reference< XConnectionPool > xDriverManager; + try { + xDriverManager = ConnectionPool::create( _rxContext ); + } catch( const Exception& ) { } + if (xDriverManager.is()) + { + OUString sUser, sPwd; + if (hasProperty(sUserProp, xRowSetProps)) + xRowSetProps->getPropertyValue(sUserProp) >>= sUser; + if (hasProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), xRowSetProps)) + xRowSetProps->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPwd; + if (!sUser.isEmpty()) + { // use user and pwd together with the url + auto aInfo(::comphelper::InitPropertySequence({ + { "user", makeAny(sUser) }, + { "password", makeAny(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", + makeAny( xConnection.getTyped() ) + ); + } + catch(Exception&) + { + OSL_FAIL("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", makeAny( 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& ) + { + OSL_FAIL( "::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, makeAny( _rChainedException ) ); +} + +namespace +{ + struct NameComponentSupport + { + const bool bCatalogs; + const bool bSchemas; + + NameComponentSupport( const bool _bCatalogs, const bool _bSchemas ) + :bCatalogs( _bCatalogs ) + ,bSchemas( _bSchemas ) + { + } + }; + + NameComponentSupport lcl_getNameComponentSupport( const Reference< XDatabaseMetaData >& _rxMetaData, EComposeRule _eComposeRule ) + { + OSL_PRECOND( _rxMetaData.is(), "lcl_getNameComponentSupport: invalid meta data!" ); + + FMetaDataSupport pCatalogCall = &XDatabaseMetaData::supportsCatalogsInDataManipulation; + FMetaDataSupport pSchemaCall = &XDatabaseMetaData::supportsSchemasInDataManipulation; + bool bIgnoreMetaData = false; + + switch ( _eComposeRule ) + { + case EComposeRule::InTableDefinitions: + pCatalogCall = &XDatabaseMetaData::supportsCatalogsInTableDefinitions; + pSchemaCall = &XDatabaseMetaData::supportsSchemasInTableDefinitions; + break; + case EComposeRule::InIndexDefinitions: + pCatalogCall = &XDatabaseMetaData::supportsCatalogsInIndexDefinitions; + pSchemaCall = &XDatabaseMetaData::supportsSchemasInIndexDefinitions; + break; + case EComposeRule::InProcedureCalls: + pCatalogCall = &XDatabaseMetaData::supportsCatalogsInProcedureCalls; + pSchemaCall = &XDatabaseMetaData::supportsSchemasInProcedureCalls; + break; + case EComposeRule::InPrivilegeDefinitions: + pCatalogCall = &XDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions; + pSchemaCall = &XDatabaseMetaData::supportsSchemasInPrivilegeDefinitions; + break; + case EComposeRule::Complete: + bIgnoreMetaData = true; + break; + case EComposeRule::InDataManipulation: + // already properly set above + break; + } + return NameComponentSupport( + bIgnoreMetaData || (_rxMetaData.get()->*pCatalogCall)(), + bIgnoreMetaData || (_rxMetaData.get()->*pSchemaCall)() + ); + } +} + +static OUString impl_doComposeTableName( const Reference< XDatabaseMetaData >& _rxMetaData, + const OUString& _rCatalog, const OUString& _rSchema, const OUString& _rName, + bool _bQuote, EComposeRule _eComposeRule ) +{ + OSL_ENSURE(_rxMetaData.is(), "impl_doComposeTableName : invalid meta data !"); + if ( !_rxMetaData.is() ) + return OUString(); + OSL_ENSURE(!_rName.isEmpty(), "impl_doComposeTableName : at least the name should be non-empty !"); + + const OUString sQuoteString = _rxMetaData->getIdentifierQuoteString(); + const NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxMetaData, _eComposeRule ) ); + + OUStringBuffer aComposedName; + + OUString sCatalogSep; + bool bCatlogAtStart = true; + if ( !_rCatalog.isEmpty() && aNameComps.bCatalogs ) + { + sCatalogSep = _rxMetaData->getCatalogSeparator(); + bCatlogAtStart = _rxMetaData->isCatalogAtStart(); + + if ( bCatlogAtStart && !sCatalogSep.isEmpty()) + { + aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog ); + aComposedName.append( sCatalogSep ); + } + } + + if ( !_rSchema.isEmpty() && aNameComps.bSchemas ) + { + aComposedName.append( _bQuote ? quoteName( sQuoteString, _rSchema ) : _rSchema ); + aComposedName.append( "." ); + } + + aComposedName.append( _bQuote ? quoteName( sQuoteString, _rName ) : _rName ); + + if ( !_rCatalog.isEmpty() + && !bCatlogAtStart + && !sCatalogSep.isEmpty() + && aNameComps.bCatalogs + ) + { + aComposedName.append( sCatalogSep ); + aComposedName.append( _bQuote ? quoteName( sQuoteString, _rCatalog ) : _rCatalog ); + } + + return aComposedName.makeStringAndClear(); +} + +OUString quoteTableName(const Reference< XDatabaseMetaData>& _rxMeta + , const OUString& _rName + , EComposeRule _eComposeRule) +{ + OUString sCatalog, sSchema, sTable; + qualifiedNameComponents(_rxMeta,_rName,sCatalog,sSchema,sTable,_eComposeRule); + return impl_doComposeTableName( _rxMeta, sCatalog, sSchema, sTable, true, _eComposeRule ); +} + +void qualifiedNameComponents(const Reference< XDatabaseMetaData >& _rxConnMetaData, const OUString& _rQualifiedName, OUString& _rCatalog, OUString& _rSchema, OUString& _rName,EComposeRule _eComposeRule) +{ + OSL_ENSURE(_rxConnMetaData.is(), "QualifiedNameComponents : invalid meta data!"); + + NameComponentSupport aNameComps( lcl_getNameComponentSupport( _rxConnMetaData, _eComposeRule ) ); + + OUString sSeparator = _rxConnMetaData->getCatalogSeparator(); + + OUString sName(_rQualifiedName); + // do we have catalogs? + if ( aNameComps.bCatalogs ) + { + if (_rxConnMetaData->isCatalogAtStart()) + { + // search for the catalog name at the beginning + sal_Int32 nIndex = sName.indexOf(sSeparator); + if (-1 != nIndex) + { + _rCatalog = sName.copy(0, nIndex); + sName = sName.copy(nIndex + 1); + } + } + else + { + // Catalog name at the end + sal_Int32 nIndex = sName.lastIndexOf(sSeparator); + if (-1 != nIndex) + { + _rCatalog = sName.copy(nIndex + 1); + sName = sName.copy(0, nIndex); + } + } + } + + if ( aNameComps.bSchemas ) + { + sal_Int32 nIndex = sName.indexOf('.'); + // OSL_ENSURE(-1 != nIndex, "QualifiedNameComponents: no schema separator!"); + if ( nIndex != -1 ) + _rSchema = sName.copy(0, nIndex); + sName = sName.copy(nIndex + 1); + } + + _rName = sName; +} + +Reference< XNumberFormatsSupplier> getNumberFormats( + const Reference< XConnection>& _rxConn, + bool _bAlloweDefault, + const Reference< XComponentContext>& _rxContext) +{ + // ask the parent of the connection (should be a DatabaseAccess) + Reference< XNumberFormatsSupplier> xReturn; + Reference< XChild> xConnAsChild(_rxConn, UNO_QUERY); + OUString sPropFormatsSupplier( "NumberFormatsSupplier" ); + if (xConnAsChild.is()) + { + Reference< XPropertySet> xConnParentProps(xConnAsChild->getParent(), UNO_QUERY); + if (xConnParentProps.is() && hasProperty(sPropFormatsSupplier, xConnParentProps)) + xConnParentProps->getPropertyValue(sPropFormatsSupplier) >>= xReturn; + } + else if(_bAlloweDefault && _rxContext.is()) + { + xReturn = NumberFormatsSupplier::createWithDefaultLocale( _rxContext ); + } + return xReturn; +} + +void TransferFormComponentProperties( + const Reference< XPropertySet>& xOldProps, + const Reference< XPropertySet>& xNewProps, + const Locale& _rLocale) +{ +try +{ + OSL_ENSURE( xOldProps.is() && xNewProps.is(), "TransferFormComponentProperties: invalid source/dest!" ); + if ( !xOldProps.is() || !xNewProps.is() ) + return; + + // First we copy all the Props, that are available in source and target and have the same description + Reference< XPropertySetInfo> xOldInfo( xOldProps->getPropertySetInfo()); + Reference< XPropertySetInfo> xNewInfo( xNewProps->getPropertySetInfo()); + + const Sequence< Property> aOldProperties = xOldInfo->getProperties(); + Sequence< Property> aNewProperties = xNewInfo->getProperties(); + int nNewLen = aNewProperties.getLength(); + + Property* pNewProps = aNewProperties.getArray(); + + OUString sPropFormatsSupplier("FormatsSupplier"); + OUString sPropCurrencySymbol("CurrencySymbol"); + OUString sPropDecimals("Decimals"); + OUString sPropEffectiveMin("EffectiveMin"); + OUString sPropEffectiveMax("EffectiveMax"); + OUString sPropEffectiveDefault("EffectiveDefault"); + OUString sPropDefaultText("DefaultText"); + OUString sPropDefaultDate("DefaultDate"); + OUString sPropDefaultTime("DefaultTime"); + OUString sPropValueMin("ValueMin"); + OUString sPropValueMax("ValueMax"); + OUString sPropDecimalAccuracy("DecimalAccuracy"); + OUString sPropClassId("ClassId"); + OUString sFormattedServiceName( "com.sun.star.form.component.FormattedField" ); + + for (const Property& rOldProp : aOldProperties) + { + if ( rOldProp.Name != "DefaultControl" && rOldProp.Name != "LabelControl" ) + { + // binary search + Property* pResult = std::lower_bound( + pNewProps, pNewProps + nNewLen, 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, makeAny(aDate)); + } + + if (hasProperty(sPropDefaultTime, xNewProps) && !bIsString) + { // Completely analogous to time + css::util::Time aTime = DBTypeConversion::toTime(getDouble(aEffectiveDefault)); + xNewProps->setPropertyValue(sPropDefaultTime, makeAny(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), makeAny(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& ) + { + OSL_FAIL( "::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; + std::copy( + _rNames.begin(), + _rNames.end(), + std::insert_iterator< std::set< OUString > >( aUsedNames, aUsedNames.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(const std::vector<bool, std::allocator<bool> >& _aSet,const Reference<XIndexAccess>& _xSource) : m_aSet(_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) + OInteractionAbort* pAbort = new OInteractionAbort; + OParameterContinuation* pParams = new OParameterContinuation; + // the request + ParametersRequest aRequest; + Reference<XIndexAccess> xWrappedParameters = new OParameterWrapper(aNewParameterSet,xParamsAsIndicies); + aRequest.Parameters = xWrappedParameters; + aRequest.Connection = _xConnection; + OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xRequest(pRequest); + // some knittings + pRequest->addContinuation(pAbort); + pRequest->addContinuation(pParams); + + // execute the request + _rxHandler->handle(xRequest); + + 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); + 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); + else + _xParams->setString(parameterIndex,_rValue); + break; + + case DataType::FLOAT: + _xParams->setFloat(parameterIndex,_rValue); + break; + case DataType::REAL: + case DataType::DOUBLE: + _xParams->setDouble(parameterIndex,_rValue); + break; + case DataType::DATE: + _xParams->setDate(parameterIndex,_rValue); + break; + case DataType::TIME: + _xParams->setTime(parameterIndex,_rValue); + break; + case DataType::TIMESTAMP: + _xParams->setTimestamp(parameterIndex,_rValue); + 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,static_cast<bool>(_rValue)); + break; + case DataType::TINYINT: + if ( _rValue.isSigned() ) + _xParams->setByte(parameterIndex,_rValue); + else + _xParams->setShort(parameterIndex,_rValue); + break; + case DataType::SMALLINT: + if ( _rValue.isSigned() ) + _xParams->setShort(parameterIndex,_rValue); + else + _xParams->setInt(parameterIndex,_rValue); + break; + case DataType::INTEGER: + if ( _rValue.isSigned() ) + _xParams->setInt(parameterIndex,_rValue); + else + _xParams->setLong(parameterIndex,_rValue); + break; + default: + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_UNKNOWN_PARA_TYPE, + "$position$", OUString::number(parameterIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,nullptr); + } + } + } +} + +void getBooleanComparisonPredicate( const OUString& _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, + const OUString& _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, + const OUString& _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, + const OUString& _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 = ; break; // Kamenicky (Czech) MS-DOS + //case 0x69: eEncoding = ; 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 000000000..a9e0caff2 --- /dev/null +++ b/connectivity/source/commontools/dbtools2.cxx @@ -0,0 +1,1028 @@ +/* -*- 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 <tools/diagnose_ex.h> +#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,const OUString& _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,OUString()); + } + + if ( (nPrecision > 0 || nScale > 0) && bUseLiteral ) + { + sal_Int32 nParenPos = sTypeName.indexOf('('); + if ( nParenPos == -1 ) + { + aSql.append(sTypeName); + aSql.append("("); + } + else + { + aSql.append(std::u16string_view(sTypeName).substr(0, ++nParenPos)); + } + + if ( nPrecision > 0 && nDataType != DataType::TIMESTAMP ) + { + aSql.append(nPrecision); + if ( (nScale > 0) || (!_sCreatePattern.isEmpty() && sCreateParams.indexOf(_sCreatePattern) != -1) ) + aSql.append(","); + } + if ( (nScale > 0) || ( !_sCreatePattern.isEmpty() && sCreateParams.indexOf(_sCreatePattern) != -1 ) || nDataType == DataType::TIMESTAMP ) + aSql.append(nScale); + + if ( nParenPos == -1 ) + aSql.append(")"); + else + { + nParenPos = sTypeName.indexOf(')',nParenPos); + aSql.append(std::u16string_view(sTypeName).substr(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 "); + aSql.append(sPrefix); + aSql.append(aDefault); + aSql.append(sPostfix); + } // if ( aDefault.getLength() ) + + return aSql.makeStringAndClear(); +} + +OUString createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,const OUString& _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(" "); + + 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(" "); + aSql.append(sAutoIncrementValue); + } + + if ( _pHelper ) + _pHelper->addComment(xColProp,aSql); + + return aSql.makeStringAndClear(); +} + + +OUString createStandardCreateStatement(const Reference< XPropertySet >& descriptor,const Reference< XConnection>& _xConnection,ISQLStatementHelper* _pHelper,const OUString& _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); + aSql.append(" ("); + + // 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)); + aSql.append(","); + } + } + 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)))) ) + .append(","); + } + + 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 "); + aSql.append(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 "); + aSql.append(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,OUString()); + const OUString sKeyStmt = ::dbtools::createStandardKeyStatement(descriptor,_xConnection); + if ( !sKeyStmt.isEmpty() ) + aSql += sKeyStmt; + else + { + if ( aSql.endsWith(",") ) + aSql = aSql.replaceAt(aSql.getLength()-1, 1, ")"); + 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" ); + } + } + + connectivity::sdbcx::OColumn* pRet = new connectivity::sdbcx::OColumn(_rName, + aField6, + sField13, + sField12, + nField11, + nField7, + nField9, + nField5, + bAutoIncrement, + false, + bIsCurrency, + _bCase, + sCatalog, + _aSchema, + _aTable); + + xProp = pRet; + 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 ) +{ + 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( OUString::createFromAscii( _pAsciiSettingName ) ) >>= 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(aInfo.begin(), + aInfo.end(), + [&_sProperty](const PropertyValue& lhs) + { return lhs.Name == _sProperty; }); + if ( pValue != aInfo.end() ) + 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, + const OUString& _sComposedName, + const OUString& _rName, + ColumnInformationMap& _rInfo) +{ + OUString sSelect = "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 ), makeAny( 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; +} +static OUString lcl_getReportEngines() +{ + return "org.openoffice.Office.DataAccess/ReportEngines"; +} + +static OUString lcl_getDefaultReportEngine() +{ + return "DefaultReportEngine"; +} + +static OUString lcl_getReportEngineNames() +{ + return "ReportEngineNames"; +} + +OUString getDefaultReportEngineServiceName(const Reference< XComponentContext >& _rxORB) +{ + ::utl::OConfigurationTreeRoot aReportEngines = ::utl::OConfigurationTreeRoot::createWithComponentContext( + _rxORB, lcl_getReportEngines(), -1, ::utl::OConfigurationTreeRoot::CM_READONLY); + + if ( aReportEngines.isValid() ) + { + OUString sDefaultReportEngineName; + aReportEngines.getNodeValue(lcl_getDefaultReportEngine()) >>= sDefaultReportEngineName; + if ( !sDefaultReportEngineName.isEmpty() ) + { + ::utl::OConfigurationNode aReportEngineNames = aReportEngines.openNode(lcl_getReportEngineNames()); + 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 const char sAgg[] = "AggregateFunction"; + 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 000000000..a6180dd00 --- /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 <tools/diagnose_ex.h> +#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), makeAny( 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 const OUString sErr("#FilterManager::getFilterComponent unknown component#"); + 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), makeAny( getComposedFilter() ) ); + break; + case FilterComponent::PublicHaving: + propagate = propagate && m_bApplyPublicFilter; + [[fallthrough]]; + case FilterComponent::LinkHaving: + if (propagate) + m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), makeAny( 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), makeAny( getComposedFilter() ) ); + if (!getFilterComponent( FilterComponent::PublicHaving ).isEmpty()) + m_xComponentAggregate->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_HAVINGCLAUSE), makeAny( getComposedHaving() ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.commontools"); + } + } + + + void FilterManager::appendFilterComponent( OUStringBuffer& io_appendTo, const OUString& 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 000000000..de317c43b --- /dev/null +++ b/connectivity/source/commontools/formattedcolumnvalue.cxx @@ -0,0 +1,292 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#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 <tools/diagnose_ex.h> +#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_xFormatter() + ,m_aNullDate( DBTypeConversion::getStandardDate() ) + ,m_nFormatKey( 0 ) + ,m_nFieldType( DataType::OTHER ) + ,m_nKeyType( NumberFormat::UNDEFINED ) + ,m_bNumericField( false ) + ,m_xColumn() + ,m_xColumnUpdate() + { + } + }; + + + 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::TIMESTAMP: + 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; + const OUString sFormatKeyProperty( "FormatKey" ); + 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::getSystemLanguage() ).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 000000000..bd114ea19 --- /dev/null +++ b/connectivity/source/commontools/parameters.cxx @@ -0,0 +1,1118 @@ +/* -*- 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 <tools/diagnose_ex.h> + +#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 aEmptyInfo; + m_aParameterInformation.swap( aEmptyInfo ); + m_aMasterFields.clear(); + m_aDetailFields.clear(); + m_sIdentifierQuoteString.clear(); + m_sSpecialCharacters.clear(); + m_xConnectionMetadata.clear(); + std::vector< bool > aEmptyArray; + m_aParametersVisited.swap( aEmptyArray ); + 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("( "); + sAdditionalFilter.append(elem); + sAdditionalFilter.append(" )"); + } + + // 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("( "); + sAdditionalHaving.append(elem); + sAdditionalHaving.append(" )"); + } + + // 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, 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) + OInteractionAbort* pAbort = new OInteractionAbort; + OParameterContinuation* pParams = new OParameterContinuation; + + // the request + ParametersRequest aRequest; + aRequest.Parameters = m_pOuterParameters.get(); + aRequest.Connection = _rxConnection; + OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aRequest ) ); + Reference< XInteractionRequest > xRequest( pRequest ); + + // some knittings + pRequest->addContinuation( pAbort ); + pRequest->addContinuation( pParams ); + + // execute the request + try + { + _rxCompletionHandler->handle( xRequest ); + } + 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::OInterfaceIteratorHelper2 aIter( m_aParameterListeners ); + Reference< XPropertySet > xProp = m_xComponent; + OSL_ENSURE(xProp.is(),"Some already released my component!"); + DatabaseParameterEvent aEvent( xProp.get(), m_pOuterParameters.get() ); + + _rClearForNotifies.clear(); + while ( aIter.hasMoreElements() && !bCanceled ) + bCanceled = !static_cast< XDatabaseParameterListener* >( 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; + } + +#define VISIT_PARAMETER( method ) \ + ::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->method; \ + externalParameterVisited( _nIndex ) \ + + + void ParameterManager::setNull( sal_Int32 _nIndex, sal_Int32 sqlType ) + { + VISIT_PARAMETER( setNull( _nIndex, sqlType ) ); + } + + + void ParameterManager::setObjectNull( sal_Int32 _nIndex, sal_Int32 sqlType, const OUString& typeName ) + { + VISIT_PARAMETER( setObjectNull( _nIndex, sqlType, typeName ) ); + } + + + void ParameterManager::setBoolean( sal_Int32 _nIndex, bool x ) + { + VISIT_PARAMETER( setBoolean( _nIndex, x ) ); + } + + + void ParameterManager::setByte( sal_Int32 _nIndex, sal_Int8 x ) + { + VISIT_PARAMETER( setByte( _nIndex, x ) ); + } + + + void ParameterManager::setShort( sal_Int32 _nIndex, sal_Int16 x ) + { + VISIT_PARAMETER( setShort( _nIndex, x ) ); + } + + + void ParameterManager::setInt( sal_Int32 _nIndex, sal_Int32 x ) + { + VISIT_PARAMETER( setInt( _nIndex, x ) ); + } + + + void ParameterManager::setLong( sal_Int32 _nIndex, sal_Int64 x ) + { + VISIT_PARAMETER( setLong( _nIndex, x ) ); + } + + + void ParameterManager::setFloat( sal_Int32 _nIndex, float x ) + { + VISIT_PARAMETER( setFloat( _nIndex, x ) ); + } + + + void ParameterManager::setDouble( sal_Int32 _nIndex, double x ) + { + VISIT_PARAMETER( setDouble( _nIndex, x ) ); + } + + + void ParameterManager::setString( sal_Int32 _nIndex, const OUString& x ) + { + VISIT_PARAMETER( setString( _nIndex, x ) ); + } + + + void ParameterManager::setBytes( sal_Int32 _nIndex, const css::uno::Sequence< sal_Int8 >& x ) + { + VISIT_PARAMETER( setBytes( _nIndex, x ) ); + } + + + void ParameterManager::setDate( sal_Int32 _nIndex, const css::util::Date& x ) + { + VISIT_PARAMETER( setDate( _nIndex, x ) ); + } + + + void ParameterManager::setTime( sal_Int32 _nIndex, const css::util::Time& x ) + { + VISIT_PARAMETER( setTime( _nIndex, x ) ); + } + + + void ParameterManager::setTimestamp( sal_Int32 _nIndex, const css::util::DateTime& x ) + { + VISIT_PARAMETER( setTimestamp( _nIndex, x ) ); + } + + + void ParameterManager::setBinaryStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length ) + { + VISIT_PARAMETER( setBinaryStream( _nIndex, x, length ) ); + } + + + void ParameterManager::setCharacterStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length ) + { + VISIT_PARAMETER( setCharacterStream( _nIndex, x, length ) ); + } + + + void ParameterManager::setObject( sal_Int32 _nIndex, const css::uno::Any& x ) + { + VISIT_PARAMETER( setObject( _nIndex, x ) ); + } + + + void ParameterManager::setObjectWithInfo( sal_Int32 _nIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) + { + VISIT_PARAMETER( setObjectWithInfo( _nIndex, x, targetSqlType, scale ) ); + } + + + void ParameterManager::setRef( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XRef>& x ) + { + VISIT_PARAMETER( setRef( _nIndex, x ) ); + } + + + void ParameterManager::setBlob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XBlob>& x ) + { + VISIT_PARAMETER( setBlob( _nIndex, x ) ); + } + + + void ParameterManager::setClob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XClob>& x ) + { + VISIT_PARAMETER( setClob( _nIndex, x ) ); + } + + + void ParameterManager::setArray( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XArray>& x ) + { + VISIT_PARAMETER( setArray( _nIndex, x ) ); + } + + + 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 000000000..ffe42419d --- /dev/null +++ b/connectivity/source/commontools/paramwrapper.cxx @@ -0,0 +1,354 @@ +/* -*- 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 <tools/diagnose_ex.h> +#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, const std::vector< sal_Int32 >& _rIndexes ) + :PropertyBase( m_aBHelper ) + ,m_aIndexes( _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[ 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 ) + { + WrappedTargetException aExceptionWrapper; + aExceptionWrapper.Context = e.Context; + aExceptionWrapper.Message = e.Message; + aExceptionWrapper.TargetException <<= e; + throw aExceptionWrapper; + } + } + 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_Base( m_aMutex ) + { + } + + + ParameterWrapperContainer::ParameterWrapperContainer( const Reference< XSingleSelectQueryAnalyzer >& _rxComposer ) + :ParameterWrapperContainer_Base( m_aMutex ) + { + 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() + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + return cppu::UnoType<XPropertySet>::get(); + } + + + sal_Bool SAL_CALL ParameterWrapperContainer::hasElements() + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + return !m_aParameters.empty(); + } + + + sal_Int32 SAL_CALL ParameterWrapperContainer::getCount() + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + return m_aParameters.size(); + } + + + Any SAL_CALL ParameterWrapperContainer::getByIndex( sal_Int32 _nIndex ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + if ( ( _nIndex < 0 ) || ( _nIndex >= static_cast<sal_Int32>(m_aParameters.size()) ) ) + throw IndexOutOfBoundsException(); + + return makeAny( Reference< XPropertySet >( m_aParameters[ _nIndex ].get() ) ); + } + + + Reference< XEnumeration > ParameterWrapperContainer::createEnumeration() + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + return new ::comphelper::OEnumerationByIndex( static_cast< XIndexAccess* >( this ) ); + } + + + void ParameterWrapperContainer::impl_checkDisposed_throw() + { + if ( rBHelper.bDisposed ) + throw DisposedException( OUString(), *this ); + } + + + void SAL_CALL ParameterWrapperContainer::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_checkDisposed_throw(); + + for (const auto& rxParam : m_aParameters) + { + rxParam->dispose(); + } + + Parameters aEmpty; + m_aParameters.swap( aEmpty ); + } + + +} // 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 000000000..0b229aa9e --- /dev/null +++ b/connectivity/source/commontools/predicateinput.cxx @@ -0,0 +1,420 @@ +/* -*- 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 <tools/diagnose_ex.h> + +#include <memory> + + +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( const OUString& _rSeparator, sal_Unicode _nFallback ) + { + OSL_ENSURE( !_rSeparator.isEmpty(), "::lcl_getSeparatorChar: invalid separator string!" ); + + sal_Unicode nReturn( _nFallback ); + if ( !_rSeparator.isEmpty() ) + 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("'") + ) + ) + { + static const char sSingleQuote[] = "'"; + + sal_Int32 nIndex = -1; + sal_Int32 nTemp = 0; + while ( -1 != ( nIndex = sQuoted.indexOf( '\'',nTemp ) ) ) + { + sQuoted = sQuoted.replaceAt( nIndex, 1, "''" ); + nTemp = nIndex+2; + } + + sQuoted = sSingleQuote + sQuoted + sSingleQuote; + } + 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& ) + { + OSL_FAIL( "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(); + 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 000000000..90c6beeed --- /dev/null +++ b/connectivity/source/commontools/propertyids.cxx @@ -0,0 +1,103 @@ +/* -*- 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); + 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 000000000..dee6f36f0 --- /dev/null +++ b/connectivity/source/commontools/sqlerror.cxx @@ -0,0 +1,300 @@ +/* -*- 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 <rtl/ustrbuf.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 ); + 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 ); + + /// 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 const OUString s_sMessagePrefix( "[OOoBase]" ); + 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 ); + } + + const char* 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 nullptr; + } + + 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 ) + { + 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 ) + { + OUStringBuffer aMessage; + + OUString sResMessage(Translate::get(lcl_getResourceErrorID(_eCondition), m_aResources)); + OSL_ENSURE( !sResMessage.isEmpty(), "SQLError_Impl::impl_getErrorMessage: illegal error condition, or invalid resource!" ); + aMessage.append( getMessagePrefix() ).append( " " ).append( sResMessage ); + + return aMessage.makeStringAndClear(); + } + + OUString SQLError_Impl::impl_getSQLState( ErrorCondition _eCondition ) + { + OUString sState = lcl_getResourceState(_eCondition); + if (sState.isEmpty()) + sState = OUString::intern( RTL_CONSTASCII_USTRINGPARAM( "S1000" ) ); + 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 000000000..01f20e9c1 --- /dev/null +++ b/connectivity/source/commontools/statementcomposer.cxx @@ -0,0 +1,304 @@ +/* -*- 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 <tools/diagnose_ex.h> +#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 ) + ,sCommand() + ,sFilter() + ,sOrder() + ,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 + const OUString sPropOrder( "Order" ); + if ( ::comphelper::hasProperty( sPropOrder, xQuery ) ) + { + OUString sOrder; + OSL_VERIFY( xQuery->getPropertyValue( sPropOrder ) >>= sOrder ); + xComposer->setOrder( sOrder ); + } + + // the filter + bool bApplyFilter = true; + const OUString sPropApply( "ApplyFilter" ); + 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 000000000..733bf5b4a --- /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, makeAny( _rWarning ) ); + } + + + void WarningsContainer::appendWarning( const SQLContext& _rContext ) + { + lcl_concatWarnings( m_aOwnWarnings, makeAny( _rContext )); + } + + + void WarningsContainer::appendWarning(const SQLWarning& _rWarning) + { + lcl_concatWarnings( m_aOwnWarnings, makeAny( _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: */ diff --git a/connectivity/source/cpool/ZConnectionPool.cxx b/connectivity/source/cpool/ZConnectionPool.cxx new file mode 100644 index 000000000..d233599a4 --- /dev/null +++ b/connectivity/source/cpool/ZConnectionPool.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 "ZConnectionPool.hxx" +#include <com/sun/star/lang/XComponent.hpp> +#include "ZPooledConnection.hxx" +#include "ZPoolCollection.hxx" +#include <connectivity/ConnectionWrapper.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + + +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 ::com::sun::star::container; +using namespace ::osl; +using namespace connectivity; + +#include <algorithm> + +void SAL_CALL OPoolTimer::onShot() +{ + m_pPool->invalidatePooledConnections(); +} + +static const char TIMEOUT_NODENAME[] = "Timeout"; + +OConnectionPool::OConnectionPool(const Reference< XDriver >& _xDriver, + const Reference< XInterface >& _xDriverNode, + const Reference< css::reflection::XProxyFactory >& _rxProxyFactory) + :m_xDriver(_xDriver) + ,m_xDriverNode(_xDriverNode) + ,m_xProxyFactory(_rxProxyFactory) + ,m_nTimeOut(10) + ,m_nALiveCount(10) +{ + OSL_ENSURE(m_xDriverNode.is(),"NO valid Driver node set!"); + Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); + + Reference<XPropertySet> xProp(m_xDriverNode,UNO_QUERY); + if(xProp.is()) + xProp->addPropertyChangeListener(TIMEOUT_NODENAME,this); + + OPoolCollection::getNodeValue(TIMEOUT_NODENAME, m_xDriverNode) >>= m_nALiveCount; + calculateTimeOuts(); + + m_xInvalidator = new OPoolTimer(this,::salhelper::TTimeValue(m_nTimeOut,0)); + m_xInvalidator->start(); +} + +OConnectionPool::~OConnectionPool() +{ + clear(false); +} + +namespace { + +struct TRemoveEventListenerFunctor +{ + OConnectionPool* m_pConnectionPool; + bool m_bDispose; + + TRemoveEventListenerFunctor(OConnectionPool* _pConnectionPool, bool _bDispose) + : m_pConnectionPool(_pConnectionPool) + ,m_bDispose(_bDispose) + { + OSL_ENSURE(m_pConnectionPool,"No connection pool!"); + } + + void dispose(const Reference<XInterface>& _xComponent) + { + Reference< XComponent > xComponent(_xComponent, UNO_QUERY); + + if ( xComponent.is() ) + { + xComponent->removeEventListener(m_pConnectionPool); + if ( m_bDispose ) + xComponent->dispose(); + } + } + + void operator()(const TPooledConnections::value_type& _aValue) + { + dispose(_aValue); + } + + void operator()(const TActiveConnectionMap::value_type& _aValue) + { + dispose(_aValue.first); + } +}; + +struct TConnectionPoolFunctor +{ + OConnectionPool* m_pConnectionPool; + + explicit TConnectionPoolFunctor(OConnectionPool* _pConnectionPool) + : m_pConnectionPool(_pConnectionPool) + { + OSL_ENSURE(m_pConnectionPool,"No connection pool!"); + } + void operator()(const TConnectionMap::value_type& _aValue) + { + std::for_each(_aValue.second.aConnections.begin(),_aValue.second.aConnections.end(),TRemoveEventListenerFunctor(m_pConnectionPool,true)); + } +}; + +} + +void OConnectionPool::clear(bool _bDispose) +{ + MutexGuard aGuard(m_aMutex); + + if(m_xInvalidator->isTicking()) + m_xInvalidator->stop(); + + std::for_each(m_aPool.begin(),m_aPool.end(),TConnectionPoolFunctor(this)); + m_aPool.clear(); + + std::for_each(m_aActiveConnections.begin(),m_aActiveConnections.end(),TRemoveEventListenerFunctor(this,_bDispose)); + m_aActiveConnections.clear(); + + Reference< XComponent > xComponent(m_xDriverNode, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(this); + Reference< XPropertySet > xProp(m_xDriverNode, UNO_QUERY); + if (xProp.is()) + xProp->removePropertyChangeListener(TIMEOUT_NODENAME, this); + + m_xDriverNode.clear(); + m_xDriver.clear(); +} + +Reference< XConnection > OConnectionPool::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo ) +{ + MutexGuard aGuard(m_aMutex); + + Reference<XConnection> xConnection; + + // create a unique id and look for it in our map + Sequence< PropertyValue > aInfo(_rInfo); + TConnectionMap::key_type nId; + OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer); + TConnectionMap::iterator aIter = m_aPool.find(nId); + + if ( m_aPool.end() != aIter ) + xConnection = getPooledConnection(aIter); + + if ( !xConnection.is() ) + xConnection = createNewConnection(_rURL,_rInfo); + + return xConnection; +} + +void SAL_CALL OConnectionPool::disposing( const css::lang::EventObject& Source ) +{ + Reference<XConnection> xConnection(Source.Source,UNO_QUERY); + if(xConnection.is()) + { + MutexGuard aGuard(m_aMutex); + TActiveConnectionMap::iterator aIter = m_aActiveConnections.find(xConnection); + OSL_ENSURE(aIter != m_aActiveConnections.end(),"OConnectionPool::disposing: Connection wasn't in pool"); + if(aIter != m_aActiveConnections.end()) + { // move the pooled connection back to the pool + aIter->second.aPos->second.nALiveCount = m_nALiveCount; + aIter->second.aPos->second.aConnections.push_back(aIter->second.xPooledConnection); + m_aActiveConnections.erase(aIter); + } + } + else + { + m_xDriverNode.clear(); + } +} + +Reference< XConnection> OConnectionPool::createNewConnection(const OUString& _rURL,const Sequence< PropertyValue >& _rInfo) +{ + // create new pooled connection + Reference< XPooledConnection > xPooledConnection = new ::connectivity::OPooledConnection(m_xDriver->connect(_rURL,_rInfo),m_xProxyFactory); + // get the new connection from the pooled connection + Reference<XConnection> xConnection = xPooledConnection->getConnection(); + if(xConnection.is()) + { + // add our own as dispose listener to know when we should put the connection back to the pool + Reference< XComponent > xComponent(xConnection, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); + + // save some information to find the right pool later on + Sequence< PropertyValue > aInfo(_rInfo); + TConnectionMap::key_type nId; + OConnectionWrapper::createUniqueId(_rURL,aInfo,nId.m_pBuffer); + TConnectionPool aPack; + + // insert the new connection and struct into the active connection map + aPack.nALiveCount = m_nALiveCount; + TActiveConnectionInfo aActiveInfo; + aActiveInfo.aPos = m_aPool.emplace(nId,aPack).first; + aActiveInfo.xPooledConnection = xPooledConnection; + m_aActiveConnections.emplace(xConnection,aActiveInfo); + + if(m_xInvalidator->isExpired()) + m_xInvalidator->start(); + } + + return xConnection; +} + +void OConnectionPool::invalidatePooledConnections() +{ + MutexGuard aGuard(m_aMutex); + TConnectionMap::iterator aIter = m_aPool.begin(); + for (; aIter != m_aPool.end(); ) + { + if(!(--(aIter->second.nALiveCount))) // connections are invalid + { + std::for_each(aIter->second.aConnections.begin(),aIter->second.aConnections.end(),TRemoveEventListenerFunctor(this,true)); + + aIter->second.aConnections.clear(); + + // look if the iterator aIter is still present in the active connection map + bool isPresent = std::any_of(m_aActiveConnections.begin(), m_aActiveConnections.end(), + [&aIter](const TActiveConnectionMap::value_type& rEntry) { return rEntry.second.aPos == aIter; }); + if(!isPresent) + {// he isn't so we can delete him + aIter = m_aPool.erase(aIter); + } + else + ++aIter; + } + else + ++aIter; + } + if(!m_aPool.empty()) + m_xInvalidator->start(); +} + +Reference< XConnection> OConnectionPool::getPooledConnection(TConnectionMap::iterator const & _rIter) +{ + Reference<XConnection> xConnection; + + if(!_rIter->second.aConnections.empty()) + { + Reference< XPooledConnection > xPooledConnection = _rIter->second.aConnections.back(); + _rIter->second.aConnections.pop_back(); + + OSL_ENSURE(xPooledConnection.is(),"Can not be null here!"); + xConnection = xPooledConnection->getConnection(); + Reference< XComponent > xComponent(xConnection, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener(this); + + TActiveConnectionInfo aActiveInfo; + aActiveInfo.aPos = _rIter; + aActiveInfo.xPooledConnection = xPooledConnection; + m_aActiveConnections[xConnection] = aActiveInfo; + } + return xConnection; +} + +void SAL_CALL OConnectionPool::propertyChange( const PropertyChangeEvent& evt ) +{ + if(TIMEOUT_NODENAME == evt.PropertyName) + { + evt.NewValue >>= m_nALiveCount; + calculateTimeOuts(); + } +} + +void OConnectionPool::calculateTimeOuts() +{ + sal_Int32 nTimeOutCorrection = 10; + if(m_nALiveCount < 100) + nTimeOutCorrection = 20; + + m_nTimeOut = m_nALiveCount / nTimeOutCorrection; + m_nALiveCount = m_nALiveCount / m_nTimeOut; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZConnectionPool.hxx b/connectivity/source/cpool/ZConnectionPool.hxx new file mode 100644 index 000000000..b05c7d1ff --- /dev/null +++ b/connectivity/source/cpool/ZConnectionPool.hxx @@ -0,0 +1,150 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZCONNECTIONPOOL_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZCONNECTIONPOOL_HXX + +#include <sal/config.h> + +#include <map> +#include <vector> + +#include <com/sun/star/sdbc/XPooledConnection.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <cppuhelper/implbase.hxx> +#include <osl/mutex.hxx> +#include <salhelper/timer.hxx> +#include <rtl/ref.hxx> +#include <rtl/digest.h> + +namespace connectivity +{ + class OConnectionPool; + + /// OPoolTimer - Invalidates the connection pool + + class OPoolTimer : public ::salhelper::Timer + { + OConnectionPool* m_pPool; + public: + OPoolTimer(OConnectionPool* _pPool,const ::salhelper::TTimeValue& Time) + : ::salhelper::Timer(Time) + ,m_pPool(_pPool) + {} + protected: + virtual void SAL_CALL onShot() override; + }; + + + // OConnectionPool - the one-instance service for PooledConnections + // manages the active connections and the connections in the pool + + // typedef for the internal structure + typedef std::vector< css::uno::Reference< css::sdbc::XPooledConnection> > TPooledConnections; + + // contains the currently pooled connections + struct TConnectionPool + { + TPooledConnections aConnections; + sal_Int32 nALiveCount; // will be decremented every time a time says to, when will reach zero the pool will be deleted + }; + + struct TDigestHolder + { + sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1]; + TDigestHolder() + { + m_pBuffer[0] = 0; + } + + }; + + // typedef TDigestHolder + + struct TDigestLess + { + bool operator() (const TDigestHolder& x, const TDigestHolder& y) const + { + sal_uInt32 i; + for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i) + ; + return i < RTL_DIGEST_LENGTH_SHA1; + } + }; + + typedef std::map< TDigestHolder,TConnectionPool,TDigestLess> TConnectionMap; + + // contains additional information about an activeconnection which is needed to put it back to the pool + struct TActiveConnectionInfo + { + TConnectionMap::iterator aPos; + css::uno::Reference< css::sdbc::XPooledConnection> xPooledConnection; + }; + + typedef std::map< css::uno::Reference< css::sdbc::XConnection>, + TActiveConnectionInfo> TActiveConnectionMap; + + class OConnectionPool : public ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener> + { + TConnectionMap m_aPool; // the pooled connections + TActiveConnectionMap m_aActiveConnections; // the currently active connections + + ::osl::Mutex m_aMutex; + ::rtl::Reference<OPoolTimer> m_xInvalidator; // invalidates the conntection pool when shot + + css::uno::Reference< css::sdbc::XDriver > m_xDriver; // the one and only driver for this connectionpool + css::uno::Reference< css::uno::XInterface > m_xDriverNode; // config node entry + css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory; + sal_Int32 m_nTimeOut; + sal_Int32 m_nALiveCount; + + private: + css::uno::Reference< css::sdbc::XConnection> createNewConnection(const OUString& _rURL, + const css::uno::Sequence< css::beans::PropertyValue >& _rInfo); + css::uno::Reference< css::sdbc::XConnection> getPooledConnection(TConnectionMap::iterator const & _rIter); + // calculate the timeout and the corresponding ALiveCount + void calculateTimeOuts(); + + protected: + // the dtor will be called from the last instance (last release call) + virtual ~OConnectionPool() override; + public: + OConnectionPool(const css::uno::Reference< css::sdbc::XDriver >& _xDriver, + const css::uno::Reference< css::uno::XInterface >& _xDriverNode, + const css::uno::Reference< css::reflection::XProxyFactory >& _rxProxyFactory); + + // delete all refs + void clear(bool _bDispose); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Reference< css::sdbc::XConnection > getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ); + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + void invalidatePooledConnections(); + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZCONNECTIONPOOL_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZConnectionWrapper.cxx b/connectivity/source/cpool/ZConnectionWrapper.cxx new file mode 100644 index 000000000..dd4519859 --- /dev/null +++ b/connectivity/source/cpool/ZConnectionWrapper.cxx @@ -0,0 +1,241 @@ +/* -*- 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 "ZConnectionWrapper.hxx" + +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; + +OConnectionWeakWrapper::OConnectionWeakWrapper(Reference< XAggregation >& _xConnection) + : OConnectionWeakWrapper_BASE(m_aMutex) +{ + setDelegation(_xConnection,m_refCount); + OSL_ENSURE(m_xConnection.is(),"OConnectionWeakWrapper: Connection must be valid!"); +} + +OConnectionWeakWrapper::~OConnectionWeakWrapper() +{ + if ( !OConnectionWeakWrapper_BASE::rBHelper.bDisposed ) + { + osl_atomic_increment( &m_refCount ); + dispose(); + } +} +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OConnectionWeakWrapper, "com.sun.star.sdbc.drivers.OConnectionWeakWrapper", "com.sun.star.sdbc.Connection") + + +Reference< XStatement > SAL_CALL OConnectionWeakWrapper::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->createStatement(); +} + +Reference< XPreparedStatement > SAL_CALL OConnectionWeakWrapper::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->prepareStatement(sql); +} + +Reference< XPreparedStatement > SAL_CALL OConnectionWeakWrapper::prepareCall( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->prepareCall(sql); +} + +OUString SAL_CALL OConnectionWeakWrapper::nativeSQL( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->nativeSQL(sql); +} + +void SAL_CALL OConnectionWeakWrapper::setAutoCommit( sal_Bool autoCommit ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + m_xConnection->setAutoCommit(autoCommit); +} + +sal_Bool SAL_CALL OConnectionWeakWrapper::getAutoCommit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getAutoCommit(); +} + +void SAL_CALL OConnectionWeakWrapper::commit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->commit(); +} + +void SAL_CALL OConnectionWeakWrapper::rollback( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->rollback(); +} + +sal_Bool SAL_CALL OConnectionWeakWrapper::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return m_xConnection->isClosed(); +} + +Reference< XDatabaseMetaData > SAL_CALL OConnectionWeakWrapper::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getMetaData(); +} + +void SAL_CALL OConnectionWeakWrapper::setReadOnly( sal_Bool readOnly ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->setReadOnly(readOnly); +} + +sal_Bool SAL_CALL OConnectionWeakWrapper::isReadOnly( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->isReadOnly(); +} + +void SAL_CALL OConnectionWeakWrapper::setCatalog( const OUString& catalog ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->setCatalog(catalog); +} + +OUString SAL_CALL OConnectionWeakWrapper::getCatalog( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getCatalog(); +} + +void SAL_CALL OConnectionWeakWrapper::setTransactionIsolation( sal_Int32 level ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->setTransactionIsolation(level); +} + +sal_Int32 SAL_CALL OConnectionWeakWrapper::getTransactionIsolation( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getTransactionIsolation(); +} + +Reference< css::container::XNameAccess > SAL_CALL OConnectionWeakWrapper::getTypeMap( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + return m_xConnection->getTypeMap(); +} + +void SAL_CALL OConnectionWeakWrapper::setTypeMap( const Reference< css::container::XNameAccess >& typeMap ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + + m_xConnection->setTypeMap(typeMap); +} + +// XCloseable +void SAL_CALL OConnectionWeakWrapper::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnectionWeakWrapper_BASE::rBHelper.bDisposed); + + } + dispose(); +} + +void OConnectionWeakWrapper::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + OConnectionWeakWrapper_BASE::disposing(); + OConnectionWrapper::disposing(); +} + +// css::lang::XUnoTunnel +IMPLEMENT_FORWARD_REFCOUNT( OConnectionWeakWrapper, OConnectionWeakWrapper_BASE ) + +css::uno::Any SAL_CALL OConnectionWeakWrapper::queryInterface( const css::uno::Type& _rType ) +{ + css::uno::Any aReturn = OConnectionWeakWrapper_BASE::queryInterface( _rType ); + if ( !aReturn.hasValue() ) + aReturn = OConnectionWrapper::queryInterface( _rType ); + return aReturn; +} + +IMPLEMENT_FORWARD_XTYPEPROVIDER2(OConnectionWeakWrapper,OConnectionWeakWrapper_BASE,OConnectionWrapper) + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZConnectionWrapper.hxx b/connectivity/source/cpool/ZConnectionWrapper.hxx new file mode 100644 index 000000000..b74fb2446 --- /dev/null +++ b/connectivity/source/cpool/ZConnectionWrapper.hxx @@ -0,0 +1,79 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZCONNECTIONWRAPPER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZCONNECTIONWRAPPER_HXX + +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <comphelper/uno3.hxx> +#include <connectivity/ConnectionWrapper.hxx> + +namespace connectivity +{ + + + // OConnectionWeakWrapper - wraps all methods to the real connection from the driver + // but when disposed it doesn't dispose the real connection + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection > OConnectionWeakWrapper_BASE; + + class OConnectionWeakWrapper : public ::cppu::BaseMutex + , public OConnectionWeakWrapper_BASE + , public OConnectionWrapper + { + protected: + // OComponentHelper + virtual void SAL_CALL disposing() override; + virtual ~OConnectionWeakWrapper() override; + public: + explicit OConnectionWeakWrapper(css::uno::Reference< css::uno::XAggregation >& _xConnection); + + // XServiceInfo + DECLARE_SERVICE_INFO(); + DECLARE_XTYPEPROVIDER() + DECLARE_XINTERFACE( ) + + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZCONNECTIONWRAPPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZDriverWrapper.cxx b/connectivity/source/cpool/ZDriverWrapper.cxx new file mode 100644 index 000000000..811f103bc --- /dev/null +++ b/connectivity/source/cpool/ZDriverWrapper.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 "ZDriverWrapper.hxx" +#include "ZConnectionPool.hxx" +#include <osl/diagnose.h> + + +namespace connectivity +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::beans; + + ODriverWrapper::ODriverWrapper( Reference< XAggregation >& _rxAggregateDriver, OConnectionPool* _pPool ) + :m_pConnectionPool(_pPool) + { + OSL_ENSURE(_rxAggregateDriver.is(), "ODriverWrapper::ODriverWrapper: invalid aggregate!"); + OSL_ENSURE(m_pConnectionPool.is(), "ODriverWrapper::ODriverWrapper: invalid connection pool!"); + + osl_atomic_increment( &m_refCount ); + if (_rxAggregateDriver.is()) + { + // transfer the (one and only) real ref to the aggregate to our member + m_xDriverAggregate = _rxAggregateDriver; + _rxAggregateDriver = nullptr; + + // a second "real" reference + m_xDriver.set(m_xDriverAggregate, UNO_QUERY); + OSL_ENSURE(m_xDriver.is(), "ODriverWrapper::ODriverWrapper: invalid aggregate (no XDriver)!"); + + // set ourself as delegator + m_xDriverAggregate->setDelegator( static_cast< XWeak* >( this ) ); + } + osl_atomic_decrement( &m_refCount ); + } + + + ODriverWrapper::~ODriverWrapper() + { + if (m_xDriverAggregate.is()) + m_xDriverAggregate->setDelegator(nullptr); + } + + + Any SAL_CALL ODriverWrapper::queryInterface( const Type& _rType ) + { + Any aReturn = ODriverWrapper_BASE::queryInterface(_rType); + return aReturn.hasValue() ? aReturn : (m_xDriverAggregate.is() ? m_xDriverAggregate->queryAggregation(_rType) : aReturn); + } + + + Reference< XConnection > SAL_CALL ODriverWrapper::connect( const OUString& url, const Sequence< PropertyValue >& info ) + { + Reference< XConnection > xConnection; + if (m_pConnectionPool.is()) + // route this through the pool + xConnection = m_pConnectionPool->getConnectionWithInfo( url, info ); + else if (m_xDriver.is()) + xConnection = m_xDriver->connect( url, info ); + + return xConnection; + } + + + sal_Bool SAL_CALL ODriverWrapper::acceptsURL( const OUString& url ) + { + return m_xDriver.is() && m_xDriver->acceptsURL(url); + } + + + Sequence< DriverPropertyInfo > SAL_CALL ODriverWrapper::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& info ) + { + Sequence< DriverPropertyInfo > aInfo; + if (m_xDriver.is()) + aInfo = m_xDriver->getPropertyInfo(url, info); + return aInfo; + } + + + sal_Int32 SAL_CALL ODriverWrapper::getMajorVersion( ) + { + return m_xDriver.is() ? m_xDriver->getMajorVersion() : 0; + } + + + sal_Int32 SAL_CALL ODriverWrapper::getMinorVersion( ) + { + return m_xDriver.is() ? m_xDriver->getMinorVersion() : 0; + } + + +} // namespace connectivity + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZDriverWrapper.hxx b/connectivity/source/cpool/ZDriverWrapper.hxx new file mode 100644 index 000000000..854542c31 --- /dev/null +++ b/connectivity/source/cpool/ZDriverWrapper.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZDRIVERWRAPPER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZDRIVERWRAPPER_HXX + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include <com/sun/star/uno/XAggregation.hpp> + + +namespace connectivity +{ + + + class OConnectionPool; + + typedef ::cppu::WeakImplHelper< css::sdbc::XDriver > ODriverWrapper_BASE; + + class ODriverWrapper final : public ODriverWrapper_BASE + { + css::uno::Reference< css::uno::XAggregation > + m_xDriverAggregate; + css::uno::Reference< css::sdbc::XDriver > + m_xDriver; + rtl::Reference<OConnectionPool> + m_pConnectionPool; + + public: + /** creates a new wrapper for a driver + @param _rxAggregateDriver + the driver to aggregate. The object will be reset to <NULL/> when returning from the ctor. + */ + ODriverWrapper( + css::uno::Reference< css::uno::XAggregation >& _rxAggregateDriver, + OConnectionPool* _pPool + ); + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + + private: + /// dtor + virtual ~ODriverWrapper() override; + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + }; + + +} // namespace connectivity + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZDRIVERWRAPPER_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZPoolCollection.cxx b/connectivity/source/cpool/ZPoolCollection.cxx new file mode 100644 index 000000000..3bc3b4960 --- /dev/null +++ b/connectivity/source/cpool/ZPoolCollection.cxx @@ -0,0 +1,482 @@ +/* -*- 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 "ZPoolCollection.hxx" +#include "ZDriverWrapper.hxx" +#include "ZConnectionPool.hxx" +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/reflection/ProxyFactory.hpp> +#include <com/sun/star/sdbc/DriverManager.hpp> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <tools/diagnose_ex.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 ::com::sun::star::container; +using namespace ::com::sun::star::reflection; +using namespace ::osl; +using namespace connectivity; + + +static OUString getConnectionPoolNodeName() +{ + return "org.openoffice.Office.DataAccess/ConnectionPool"; +} + +static OUString getEnablePoolingNodeName() +{ + return "EnablePooling"; +} + +static OUString getDriverNameNodeName() +{ + return "DriverName"; +} + +static OUString getDriverSettingsNodeName() +{ + return "DriverSettings"; +} + +static OUString getEnableNodeName() +{ + return "Enable"; +} + + +OPoolCollection::OPoolCollection(const Reference< XComponentContext >& _rxContext) + :m_xContext(_rxContext) +{ + // bootstrap all objects supporting the .sdb.Driver service + m_xManager = DriverManager::create( m_xContext ); + + m_xProxyFactory = ProxyFactory::create( m_xContext ); + + Reference<XPropertySet> xProp(getConfigPoolRoot(),UNO_QUERY); + if ( xProp.is() ) + xProp->addPropertyChangeListener(getEnablePoolingNodeName(),this); + // attach as desktop listener to know when we have to release our pools + osl_atomic_increment( &m_refCount ); + { + + m_xDesktop = css::frame::Desktop::create( m_xContext ); + m_xDesktop->addTerminateListener(this); + + } + osl_atomic_decrement( &m_refCount ); +} + +OPoolCollection::~OPoolCollection() +{ + clearConnectionPools(false); +} + +Reference< XConnection > SAL_CALL OPoolCollection::getConnection( const OUString& _rURL ) +{ + return getConnectionWithInfo(_rURL,Sequence< PropertyValue >()); +} + +Reference< XConnection > SAL_CALL OPoolCollection::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo ) +{ + MutexGuard aGuard(m_aMutex); + Reference< XConnection > xConnection; + Reference< XDriver > xDriver; + Reference< XInterface > xDriverNode; + OUString sImplName; + if(isPoolingEnabledByUrl(_rURL,xDriver,sImplName,xDriverNode) && xDriver.is()) + { + OConnectionPool* pConnectionPool = getConnectionPool(sImplName,xDriver,xDriverNode); + + if(pConnectionPool) + xConnection = pConnectionPool->getConnectionWithInfo(_rURL,_rInfo); + } + else if(xDriver.is()) + xConnection = xDriver->connect(_rURL,_rInfo); + + return xConnection; +} + +void SAL_CALL OPoolCollection::setLoginTimeout( sal_Int32 seconds ) +{ + MutexGuard aGuard(m_aMutex); + m_xManager->setLoginTimeout(seconds); +} + +sal_Int32 SAL_CALL OPoolCollection::getLoginTimeout( ) +{ + MutexGuard aGuard(m_aMutex); + return m_xManager->getLoginTimeout(); +} + +OUString SAL_CALL OPoolCollection::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL OPoolCollection::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +Sequence< OUString > SAL_CALL OPoolCollection::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + +//---------------------------------------OPoolCollection---------------------------------- +Reference< XInterface > OPoolCollection::CreateInstance(const Reference< XMultiServiceFactory >& _rxFactory) +{ + return static_cast<XDriverManager*>(new OPoolCollection(comphelper::getComponentContext(_rxFactory))); +} + + +OUString OPoolCollection::getImplementationName_Static( ) +{ + return "com.sun.star.sdbc.OConnectionPool"; +} + + +Sequence< OUString > OPoolCollection::getSupportedServiceNames_Static( ) +{ + Sequence< OUString > aSupported { "com.sun.star.sdbc.ConnectionPool" }; + return aSupported; +} + +Reference< XDriver > SAL_CALL OPoolCollection::getDriverByURL( const OUString& _rURL ) +{ + // returns the original driver when no connection pooling is enabled else it returns the proxy + MutexGuard aGuard(m_aMutex); + + Reference< XDriver > xDriver; + Reference< XInterface > xDriverNode; + OUString sImplName; + if(isPoolingEnabledByUrl(_rURL,xDriver,sImplName,xDriverNode)) + { + Reference< XDriver > xExistentProxy; + // look if we already have a proxy for this driver + for (const auto& [rxDriver, rxDriverRef] : m_aDriverProxies) + { + // hold the proxy alive as long as we're in this loop round + xExistentProxy = rxDriverRef; + + if (xExistentProxy.is() && (rxDriver.get() == xDriver.get())) + // already created a proxy for this + break; + } + if (xExistentProxy.is()) + { + xDriver = xExistentProxy; + } + else + { // create a new proxy for the driver + // this allows us to control the connections created by it + Reference< XAggregation > xDriverProxy = m_xProxyFactory->createProxy(xDriver.get()); + OSL_ENSURE(xDriverProxy.is(), "OConnectionPool::getDriverByURL: invalid proxy returned by the proxy factory!"); + + OConnectionPool* pConnectionPool = getConnectionPool(sImplName,xDriver,xDriverNode); + xDriver = new ODriverWrapper(xDriverProxy, pConnectionPool); + } + } + + return xDriver; +} + +bool OPoolCollection::isDriverPoolingEnabled(const OUString& _sDriverImplName, + Reference< XInterface >& _rxDriverNode) +{ + bool bEnabled = false; + Reference<XInterface> xConnectionPoolRoot = getConfigPoolRoot(); + // then look for which of them settings are stored in the configuration + Reference< XNameAccess > xDirectAccess(openNode(getDriverSettingsNodeName(),xConnectionPoolRoot),UNO_QUERY); + + if(xDirectAccess.is()) + { + Sequence< OUString > aDriverKeys = xDirectAccess->getElementNames(); + const OUString* pDriverKeys = aDriverKeys.getConstArray(); + const OUString* pDriverKeysEnd = pDriverKeys + aDriverKeys.getLength(); + for (;pDriverKeys != pDriverKeysEnd; ++pDriverKeys) + { + // the name of the driver in this round + if(_sDriverImplName == *pDriverKeys) + { + _rxDriverNode = openNode(*pDriverKeys,xDirectAccess); + if(_rxDriverNode.is()) + getNodeValue(getEnableNodeName(),_rxDriverNode) >>= bEnabled; + break; + } + } + } + return bEnabled; +} + +bool OPoolCollection::isPoolingEnabled() +{ + // the config node where all pooling relevant info are stored under + Reference<XInterface> xConnectionPoolRoot = getConfigPoolRoot(); + + // the global "enabled" flag + bool bEnabled = false; + if(xConnectionPoolRoot.is()) + getNodeValue(getEnablePoolingNodeName(),xConnectionPoolRoot) >>= bEnabled; + return bEnabled; +} + +Reference<XInterface> const & OPoolCollection::getConfigPoolRoot() +{ + if(!m_xConfigNode.is()) + m_xConfigNode = createWithProvider( + css::configuration::theDefaultProvider::get(m_xContext), + getConnectionPoolNodeName()); + return m_xConfigNode; +} + +bool OPoolCollection::isPoolingEnabledByUrl(const OUString& _sUrl, + Reference< XDriver >& _rxDriver, + OUString& _rsImplName, + Reference< XInterface >& _rxDriverNode) +{ + bool bEnabled = false; + _rxDriver = m_xManager->getDriverByURL(_sUrl); + if (_rxDriver.is() && isPoolingEnabled()) + { + Reference< XServiceInfo > xSerivceInfo(_rxDriver,UNO_QUERY); + OSL_ENSURE(xSerivceInfo.is(),"Each driver should have a XServiceInfo interface!"); + + if(xSerivceInfo.is()) + { + // look for the implementation name of the driver + _rsImplName = xSerivceInfo->getImplementationName(); + bEnabled = isDriverPoolingEnabled(_rsImplName,_rxDriverNode); + } + } + return bEnabled; +} + +void OPoolCollection::clearConnectionPools(bool _bDispose) +{ + for(auto& rEntry : m_aPools) + { + rEntry.second->clear(_bDispose); + } + m_aPools.clear(); +} + +OConnectionPool* OPoolCollection::getConnectionPool(const OUString& _sImplName, + const Reference< XDriver >& _xDriver, + const Reference< XInterface >& _xDriverNode) +{ + OConnectionPool *pRet = nullptr; + OConnectionPools::const_iterator aFind = m_aPools.find(_sImplName); + if (aFind != m_aPools.end()) + pRet = aFind->second.get(); + else if (_xDriver.is() && _xDriverNode.is()) + { + Reference<XPropertySet> xProp(_xDriverNode,UNO_QUERY); + if(xProp.is()) + xProp->addPropertyChangeListener(getEnableNodeName(),this); + OConnectionPool* pConnectionPool = new OConnectionPool(_xDriver,_xDriverNode,m_xProxyFactory); + aFind = m_aPools.emplace(_sImplName,pConnectionPool).first; + pRet = aFind->second.get(); + } + + OSL_ENSURE(pRet, "Could not query DriverManager from ConnectionPool!"); + + return pRet; +} + +Reference< XInterface > OPoolCollection::createWithProvider(const Reference< XMultiServiceFactory >& _rxConfProvider, + const OUString& _rPath) +{ + OSL_ASSERT(_rxConfProvider.is()); + Sequence< Any > args(1); + args[0] <<= NamedValue( "nodepath", makeAny(_rPath)); + Reference< XInterface > xInterface( + _rxConfProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + args)); + OSL_ENSURE( + xInterface.is(), + "::createWithProvider: could not create the node access!"); + return xInterface; +} + +Reference<XInterface> OPoolCollection::openNode(const OUString& _rPath,const Reference<XInterface>& _xTreeNode) throw() +{ + Reference< XHierarchicalNameAccess > xHierarchyAccess(_xTreeNode, UNO_QUERY); + Reference< XNameAccess > xDirectAccess(_xTreeNode, UNO_QUERY); + Reference< XInterface > xNode; + + try + { + if (xDirectAccess.is() && xDirectAccess->hasByName(_rPath)) + { + xNode.set(xDirectAccess->getByName(_rPath), css::uno::UNO_QUERY); + SAL_WARN_IF( + !xNode.is(), "connectivity.cpool", + "OConfigurationNode::openNode: could not open the node!"); + } + else if (xHierarchyAccess.is()) + { + xNode.set( + xHierarchyAccess->getByHierarchicalName(_rPath), + css::uno::UNO_QUERY); + SAL_WARN_IF( + !xNode.is(), "connectivity.cpool", + "OConfigurationNode::openNode: could not open the node!"); + } + + } + catch(const NoSuchElementException&) + { + SAL_WARN("connectivity.cpool", "::openNode: there is no element named " << + _rPath << "!"); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("connectivity.cpool", "OConfigurationNode::openNode: caught an exception while retrieving the node"); + } + return xNode; +} + +Any OPoolCollection::getNodeValue(const OUString& _rPath,const Reference<XInterface>& _xTreeNode) throw() +{ + Reference< XHierarchicalNameAccess > xHierarchyAccess(_xTreeNode, UNO_QUERY); + Reference< XNameAccess > xDirectAccess(_xTreeNode, UNO_QUERY); + Any aReturn; + try + { + if (xDirectAccess.is() && xDirectAccess->hasByName(_rPath) ) + { + aReturn = xDirectAccess->getByName(_rPath); + } + else if (xHierarchyAccess.is()) + { + aReturn = xHierarchyAccess->getByHierarchicalName(_rPath); + } + } + catch(const NoSuchElementException&) + { + TOOLS_WARN_EXCEPTION("connectivity.cpool", "" ); + } + return aReturn; +} + +void SAL_CALL OPoolCollection::queryTermination( const EventObject& /*Event*/ ) +{ +} + +void SAL_CALL OPoolCollection::notifyTermination( const EventObject& /*Event*/ ) +{ + clearDesktop(); +} + +void SAL_CALL OPoolCollection::disposing( const EventObject& Source ) +{ + MutexGuard aGuard(m_aMutex); + if ( m_xDesktop == Source.Source ) + { + clearDesktop(); + } + else + { + try + { + Reference<XPropertySet> xProp(Source.Source,UNO_QUERY); + if(Source.Source == m_xConfigNode) + { + if ( xProp.is() ) + xProp->removePropertyChangeListener(getEnablePoolingNodeName(),this); + m_xConfigNode.clear(); + } + else if ( xProp.is() ) + xProp->removePropertyChangeListener(getEnableNodeName(),this); + } + catch(const Exception&) + { + SAL_WARN("connectivity.cpool", "Exception caught"); + } + } +} + +void SAL_CALL OPoolCollection::propertyChange( const css::beans::PropertyChangeEvent& evt ) +{ + MutexGuard aGuard(m_aMutex); + if(evt.Source == m_xConfigNode) + { + bool bEnabled = true; + evt.NewValue >>= bEnabled; + if(!bEnabled ) + { + m_aDriverProxies.clear(); + m_aDriverProxies = MapDriver2DriverRef(); + clearConnectionPools(false); + } + } + else if(evt.Source.is()) + { + bool bEnabled = true; + evt.NewValue >>= bEnabled; + if(!bEnabled) + { + OUString sThisDriverName; + getNodeValue(getDriverNameNodeName(),evt.Source) >>= sThisDriverName; + // 1st release the driver + // look if we already have a proxy for this driver + MapDriver2DriverRef::iterator aLookup = m_aDriverProxies.begin(); + while( aLookup != m_aDriverProxies.end()) + { + MapDriver2DriverRef::iterator aFind = aLookup; + Reference<XServiceInfo> xInfo(aLookup->first,UNO_QUERY); + ++aLookup; + if(xInfo.is() && xInfo->getImplementationName() == sThisDriverName) + m_aDriverProxies.erase(aFind); + } + + // 2nd clear the connectionpool + OConnectionPools::iterator aFind = m_aPools.find(sThisDriverName); + if(aFind != m_aPools.end()) + { + aFind->second->clear(false); + m_aPools.erase(aFind); + } + } + } +} + +void OPoolCollection::clearDesktop() +{ + clearConnectionPools(true); + if ( m_xDesktop.is() ) + m_xDesktop->removeTerminateListener(this); + m_xDesktop.clear(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZPoolCollection.hxx b/connectivity/source/cpool/ZPoolCollection.hxx new file mode 100644 index 000000000..7671e3249 --- /dev/null +++ b/connectivity/source/cpool/ZPoolCollection.hxx @@ -0,0 +1,141 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZPOOLCOLLECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZPOOLCOLLECTION_HXX + +#include <sal/config.h> + +#include <map> + +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/weakref.hxx> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbc/XDriverManager2.hpp> +#include <com/sun/star/sdbc/XConnectionPool.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/frame/XDesktop2.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> + +namespace connectivity +{ + class OConnectionPool; + + // OPoolCollection - the one-instance service for PooledConnections + // manages the active connections and the connections in the pool + + typedef ::cppu::WeakImplHelper< css::sdbc::XConnectionPool, + css::lang::XServiceInfo, + css::frame::XTerminateListener, + css::beans::XPropertyChangeListener + > OPoolCollection_Base; + + /// OPoolCollection: control the whole connection pooling for oo + class OPoolCollection : public OPoolCollection_Base + { + + + typedef std::map<OUString, rtl::Reference<OConnectionPool>> OConnectionPools; + + typedef std::map< + css::uno::Reference< css::sdbc::XDriver >, + css::uno::WeakReference< css::sdbc::XDriver >> + MapDriver2DriverRef; + + MapDriver2DriverRef m_aDriverProxies; + ::osl::Mutex m_aMutex; + OConnectionPools m_aPools; // the driver pools + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::sdbc::XDriverManager2 > m_xManager; + css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory; + css::uno::Reference< css::uno::XInterface > m_xConfigNode; // config node for general connection pooling + css::uno::Reference< css::frame::XDesktop2> m_xDesktop; + + private: + OPoolCollection(const OPoolCollection&) = delete; + int operator= (const OPoolCollection&) = delete; + + explicit OPoolCollection( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + // some configuration helper methods + css::uno::Reference< css::uno::XInterface > const & getConfigPoolRoot(); + static css::uno::Reference< css::uno::XInterface > createWithProvider( const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxConfProvider, + const OUString& _rPath); + static css::uno::Reference< css::uno::XInterface > openNode( const OUString& _rPath, + const css::uno::Reference< css::uno::XInterface >& _xTreeNode) throw(); + bool isPoolingEnabled(); + bool isDriverPoolingEnabled(const OUString& _sDriverImplName, + css::uno::Reference< css::uno::XInterface >& _rxDriverNode); + bool isPoolingEnabledByUrl( const OUString& _sUrl, + css::uno::Reference< css::sdbc::XDriver >& _rxDriver, + OUString& _rsImplName, + css::uno::Reference< css::uno::XInterface >& _rxDriverNode); + + OConnectionPool* getConnectionPool( const OUString& _sImplName, + const css::uno::Reference< css::sdbc::XDriver >& _xDriver, + const css::uno::Reference< css::uno::XInterface >& _rxDriverNode); + void clearConnectionPools(bool _bDispose); + void clearDesktop(); + protected: + virtual ~OPoolCollection() override; + public: + + static css::uno::Any getNodeValue( const OUString& _rPath, + const css::uno::Reference< css::uno::XInterface>& _xTreeNode)throw(); + + // XDriverManager + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& url ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override; + virtual sal_Int32 SAL_CALL getLoginTimeout( ) override; + + //XDriverAccess + virtual css::uno::Reference< css::sdbc::XDriver > SAL_CALL getDriverByURL( const OUString& url ) override; + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XServiceInfo - static methods + static css::uno::Reference< css::uno::XInterface > CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZPOOLCOLLECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZPooledConnection.cxx b/connectivity/source/cpool/ZPooledConnection.cxx new file mode 100644 index 000000000..2d0b83707 --- /dev/null +++ b/connectivity/source/cpool/ZPooledConnection.cxx @@ -0,0 +1,72 @@ +/* -*- 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 "ZPooledConnection.hxx" +#include "ZConnectionWrapper.hxx" +#include <comphelper/types.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::reflection; +using namespace connectivity; +using namespace ::osl; + +OPooledConnection::OPooledConnection(const Reference< XConnection >& _xConnection, + const Reference< css::reflection::XProxyFactory >& _rxProxyFactory) + : OPooledConnection_Base(m_aMutex) + ,m_xRealConnection(_xConnection) + ,m_xProxyFactory(_rxProxyFactory) +{ + +} + +// OComponentHelper +void SAL_CALL OPooledConnection::disposing() +{ + MutexGuard aGuard(m_aMutex); + if (m_xComponent.is()) + m_xComponent->removeEventListener(this); + m_xComponent.clear(); + ::comphelper::disposeComponent(m_xRealConnection); +} + +// XEventListener +void SAL_CALL OPooledConnection::disposing( const EventObject& /*Source*/ ) +{ +m_xComponent.clear(); +} + +//XPooledConnection +Reference< XConnection > OPooledConnection::getConnection() +{ + if(!m_xComponent.is() && m_xRealConnection.is()) + { + Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(m_xRealConnection.get()); + m_xComponent = new OConnectionWeakWrapper(xConProxy); + // register as event listener for the new connection + if (m_xComponent.is()) + m_xComponent->addEventListener(this); + } + return Reference< XConnection >(m_xComponent,UNO_QUERY); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/ZPooledConnection.hxx b/connectivity/source/cpool/ZPooledConnection.hxx new file mode 100644 index 000000000..5f529f0c3 --- /dev/null +++ b/connectivity/source/cpool/ZPooledConnection.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZPOOLEDCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZPOOLEDCONNECTION_HXX + +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/sdbc/XPooledConnection.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/reflection/XProxyFactory.hpp> + + +namespace connectivity +{ + + // OPooledConnection - + // allows to pool a real connection + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XPooledConnection + ,css::lang::XEventListener> OPooledConnection_Base; + + class OPooledConnection : public ::cppu::BaseMutex + ,public OPooledConnection_Base + { + css::uno::Reference< css::sdbc::XConnection > m_xRealConnection; // the connection from driver + css::uno::Reference< css::lang::XComponent > m_xComponent; // the connection which wraps the real connection + css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory; + public: + // OComponentHelper + virtual void SAL_CALL disposing() override; + + OPooledConnection(const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const css::uno::Reference< css::reflection::XProxyFactory >& _rxProxyFactory); + + //XPooledConnection + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + }; + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_CPOOL_ZPOOLEDCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/Zregistration.cxx b/connectivity/source/cpool/Zregistration.cxx new file mode 100644 index 000000000..eb65e6158 --- /dev/null +++ b/connectivity/source/cpool/Zregistration.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 <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include "ZPoolCollection.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; +using namespace connectivity; + +extern "C" +{ + + +SAL_DLLPUBLIC_EXPORT void* dbpool2_component_getFactory(const char* _pImplName, void * _pServiceManager, void* /*_pRegistryKey*/) +{ + void* pRet = nullptr; + + if (OPoolCollection::getImplementationName_Static().equalsAscii(_pImplName)) + { + Reference< XSingleServiceFactory > xFactory( + ::cppu::createOneInstanceFactory( + static_cast<css::lang::XMultiServiceFactory *>( + _pServiceManager), + OPoolCollection::getImplementationName_Static(), + OPoolCollection::CreateInstance, + OPoolCollection::getSupportedServiceNames_Static() + ) + ); + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} + +} // extern "C" + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/cpool/dbpool2.component b/connectivity/source/cpool/dbpool2.component new file mode 100644 index 000000000..6f41d8ace --- /dev/null +++ b/connectivity/source/cpool/dbpool2.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="dbpool2" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.sdbc.OConnectionPool"> + <service name="com.sun.star.sdbc.ConnectionPool"/> + </implementation> +</component> diff --git a/connectivity/source/dbtools/dbtools.component b/connectivity/source/dbtools/dbtools.component new file mode 100644 index 000000000..424b26625 --- /dev/null +++ b/connectivity/source/dbtools/dbtools.component @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="dbtools" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.helper.DatabaseMetaDataResultSet"> + <service name="com.sun.star.sdbc.ResultSet"/> + </implementation> + <implementation name="org.openoffice.comp.helper.ParameterSubstitution"> + <service name="com.sun.star.sdb.ParameterSubstitution"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/ado/ACallableStatement.cxx b/connectivity/source/drivers/ado/ACallableStatement.cxx new file mode 100644 index 000000000..d572a8f99 --- /dev/null +++ b/connectivity/source/drivers/ado/ACallableStatement.cxx @@ -0,0 +1,223 @@ +/* -*- 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 <ado/ACallableStatement.hxx> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/queryinterface.hxx> + +using namespace connectivity::ado; +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::container; + +IMPLEMENT_SERVICE_INFO(OCallableStatement,"com.sun.star.sdbcx.ACallableStatement","com.sun.star.sdbc.CallableStatement"); + +#define GET_PARAM() \ + ADOParameter* pParam = nullptr; \ + m_pParameters->get_Item(OLEVariant(sal_Int32(columnIndex-1)),&pParam); \ + if(pParam) \ + pParam->get_Value(&m_aValue); + +//************ Class: java.sql.CallableStatement + +OCallableStatement::OCallableStatement( OConnection* _pConnection, const OUString& sql ) + : OPreparedStatement( _pConnection, sql ) +{ + m_Command.put_CommandType(adCmdStoredProc); +} + + +Any SAL_CALL OCallableStatement::queryInterface( const Type & rType ) +{ + Any aRet = OPreparedStatement::queryInterface(rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< XRow*>(this)); +} + + +sal_Bool SAL_CALL OCallableStatement::wasNull( ) +{ + return m_aValue.isNull(); +} + + +sal_Bool SAL_CALL OCallableStatement::getBoolean( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getBool(); +} + +sal_Int8 SAL_CALL OCallableStatement::getByte( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getInt8(); +} + +Sequence< sal_Int8 > SAL_CALL OCallableStatement::getBytes( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getByteSequence(); +} + +css::util::Date SAL_CALL OCallableStatement::getDate( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getDate(); +} + +double SAL_CALL OCallableStatement::getDouble( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getDouble(); +} + + +float SAL_CALL OCallableStatement::getFloat( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getFloat(); +} + + +sal_Int32 SAL_CALL OCallableStatement::getInt( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getInt32(); +} + + +sal_Int64 SAL_CALL OCallableStatement::getLong( sal_Int32 columnIndex ) +{ + GET_PARAM() + return static_cast<sal_Int64>(m_aValue.getCurrency().int64); +} + + +Any SAL_CALL OCallableStatement::getObject( sal_Int32 /*columnIndex*/, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getObject", *this ); + return Any(); +} + + +sal_Int16 SAL_CALL OCallableStatement::getShort( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getInt16(); +} + + +OUString SAL_CALL OCallableStatement::getString( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getString(); +} + + + css::util::Time SAL_CALL OCallableStatement::getTime( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getTime(); +} + + + css::util::DateTime SAL_CALL OCallableStatement::getTimestamp( sal_Int32 columnIndex ) +{ + GET_PARAM() + return m_aValue.getDateTime(); +} + + +void SAL_CALL OCallableStatement::registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ ) +{ + ADOParameter* pParam = nullptr; + m_pParameters->get_Item(OLEVariant(sal_Int32(parameterIndex-1)),&pParam); + if(pParam) + { + pParam->put_Type(ADOS::MapJdbc2ADOType(sqlType,m_pConnection->getEngineType())); + pParam->put_Direction(adParamOutput); + } +} + +void SAL_CALL OCallableStatement::registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) +{ + ADOParameter* pParam = nullptr; + m_pParameters->get_Item(OLEVariant(sal_Int32(parameterIndex-1)),&pParam); + if(pParam) + { + pParam->put_Type(ADOS::MapJdbc2ADOType(sqlType,m_pConnection->getEngineType())); + pParam->put_Direction(adParamOutput); + pParam->put_NumericScale(static_cast<sal_Int8>(scale)); + } +} + + +Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getBinaryStream( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getBinaryStream", *this ); + return nullptr; +} + +Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getCharacterStream( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getCharacterStream", *this ); + return nullptr; +} + + +Reference< XArray > SAL_CALL OCallableStatement::getArray( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getArray", *this ); + return nullptr; +} + + +Reference< XClob > SAL_CALL OCallableStatement::getClob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getClob", *this ); + return nullptr; +} + +Reference< XBlob > SAL_CALL OCallableStatement::getBlob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getBlob", *this ); + return nullptr; +} + + +Reference< XRef > SAL_CALL OCallableStatement::getRef( sal_Int32 /*columnIndex*/) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRef", *this ); + return nullptr; +} + + +void SAL_CALL OCallableStatement::acquire() throw() +{ + OPreparedStatement::acquire(); +} + +void SAL_CALL OCallableStatement::release() throw() +{ + OPreparedStatement::release(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ACatalog.cxx b/connectivity/source/drivers/ado/ACatalog.cxx new file mode 100644 index 000000000..efab28344 --- /dev/null +++ b/connectivity/source/drivers/ado/ACatalog.cxx @@ -0,0 +1,115 @@ +/* -*- 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 <ado/ACatalog.hxx> +#include <ado/AConnection.hxx> +#include <ado/AGroups.hxx> +#include <ado/AUsers.hxx> +#include <ado/ATables.hxx> +#include <ado/AViews.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> + + +using namespace connectivity; +using namespace connectivity::ado; + +OCatalog::OCatalog(_ADOCatalog* _pCatalog,OConnection* _pCon) : connectivity::sdbcx::OCatalog(_pCon) + ,m_aCatalog(_pCatalog) + ,m_pConnection(_pCon) +{ +} + +OCatalog::~OCatalog() +{ + if(m_aCatalog.IsValid()) + m_aCatalog.putref_ActiveConnection(nullptr); + m_aCatalog.clear(); +} + +void OCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + + WpADOTables aTables(m_aCatalog.get_Tables()); + if ( aTables.IsValid() ) + { + aTables.Refresh(); + sal_Int32 nCount = aTables.GetItemCount(); + aVector.reserve(nCount); + for(sal_Int32 i=0;i< nCount;++i) + { + WpADOTable aElement = aTables.GetItem(i); + if ( aElement.IsValid() ) + { + OUString sTypeName = aElement.get_Type(); + if ( !sTypeName.equalsIgnoreAsciiCase("SYSTEM TABLE") + && !sTypeName.equalsIgnoreAsciiCase("ACCESS TABLE") ) + aVector.push_back(aElement.get_Name()); + } + } + } + + if(m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset( new OTables(this,m_aMutex,aVector,aTables,m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) ); +} + +void OCatalog::refreshViews() +{ + ::std::vector< OUString> aVector; + + WpADOViews aViews = m_aCatalog.get_Views(); + aViews.fillElementNames(aVector); + + if(m_pViews) + m_pViews->reFill(aVector); + else + m_pViews.reset( new OViews(this,m_aMutex,aVector,aViews,m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) ); +} + +void OCatalog::refreshGroups() +{ + ::std::vector< OUString> aVector; + + WpADOGroups aGroups = m_aCatalog.get_Groups(); + aGroups.fillElementNames(aVector); + + if(m_pGroups) + m_pGroups->reFill(aVector); + else + m_pGroups.reset( new OGroups(this,m_aMutex,aVector,aGroups,m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) ); +} + +void OCatalog::refreshUsers() +{ + ::std::vector< OUString> aVector; + + WpADOUsers aUsers = m_aCatalog.get_Users(); + aUsers.fillElementNames(aVector); + + if(m_pUsers) + m_pUsers->reFill(aVector); + else + m_pUsers.reset( new OUsers(this,m_aMutex,aVector,aUsers,m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AColumn.cxx b/connectivity/source/drivers/ado/AColumn.cxx new file mode 100644 index 000000000..b7175d54c --- /dev/null +++ b/connectivity/source/drivers/ado/AColumn.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 <ado/AColumn.hxx> +#include <ado/AConnection.hxx> +#include <ado/Awrapado.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <comphelper/extract.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <ado/ACatalog.hxx> + +using namespace ::comphelper; + +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +void WpADOColumn::Create() +{ + _ADOColumn* pColumn = nullptr; + HRESULT hr = CoCreateInstance(ADOS::CLSID_ADOCOLUMN_25, + nullptr, + CLSCTX_INPROC_SERVER, + ADOS::IID_ADOCOLUMN_25, + reinterpret_cast<void**>(&pColumn) ); + + + if( !FAILED( hr ) ) + { + operator=( pColumn ); + pColumn->Release( ); + } +} + +OAdoColumn::OAdoColumn(bool _bCase,OConnection* _pConnection,_ADOColumn* _pColumn) + : connectivity::sdbcx::OColumn(_bCase) + ,m_pConnection(_pConnection) +{ + construct(); + OSL_ENSURE(_pColumn,"Column can not be null!"); + m_aColumn = WpADOColumn(_pColumn); + // m_aColumn.put_ParentCatalog(_pConnection->getAdoCatalog()->getCatalog()); + fillPropertyValues(); +} + +OAdoColumn::OAdoColumn(bool _bCase,OConnection* _pConnection) + : connectivity::sdbcx::OColumn(_bCase) + ,m_pConnection(_pConnection) +{ + m_aColumn.Create(); + m_aColumn.put_ParentCatalog(_pConnection->getAdoCatalog()->getCatalog()); + construct(); + fillPropertyValues(); + m_Type = DataType::OTHER; +} + + +Sequence< sal_Int8 > OAdoColumn::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OAdoColumn::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OAdoColumn>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : OColumn_ADO::getSomething(rId); +} + +void OAdoColumn::construct() +{ + sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY; + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING, nAttrib,&m_IsAscending, cppu::UnoType<bool>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RELATEDCOLUMN), PROPERTY_ID_RELATEDCOLUMN, nAttrib,&m_ReferencedColumn, ::cppu::UnoType<OUString>::get()); +} + +void OAdoColumn::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + if(m_aColumn.IsValid()) + { + const char* pAdoPropertyName = nullptr; + + switch(nHandle) + { + case PROPERTY_ID_ISASCENDING: + m_aColumn.put_SortOrder(::cppu::any2bool(rValue) ? adSortAscending : adSortDescending); + break; + case PROPERTY_ID_RELATEDCOLUMN: + { + OUString aVal; + rValue >>= aVal; + m_aColumn.put_RelatedColumn(aVal); + } + break; + case PROPERTY_ID_NAME: + { + OUString aVal; + rValue >>= aVal; + m_aColumn.put_Name(aVal); + } + break; + case PROPERTY_ID_TYPE: + { + sal_Int32 nVal=0; + rValue >>= nVal; + m_aColumn.put_Type(ADOS::MapJdbc2ADOType(nVal,m_pConnection->getEngineType())); + } + break; + case PROPERTY_ID_TYPENAME: + // rValue <<= m_pTable->getCatalog()->getConnection()->getTypeInfo()->find(); + break; + case PROPERTY_ID_PRECISION: + { + sal_Int32 nVal=0; + rValue >>= nVal; + m_aColumn.put_Precision(nVal); + } + break; + case PROPERTY_ID_SCALE: + { + sal_Int32 nVal=0; + rValue >>= nVal; + if ( !m_IsCurrency ) + m_aColumn.put_NumericScale(static_cast<sal_Int8>(nVal)); + } + break; + case PROPERTY_ID_ISNULLABLE: + { + sal_Int32 nVal=0; + rValue >>= nVal; + if ( nVal == ColumnValue::NULLABLE ) + m_aColumn.put_Attributes( adColNullable ); + } + break; + case PROPERTY_ID_ISROWVERSION: + break; + + case PROPERTY_ID_ISAUTOINCREMENT: + OTools::putValue( m_aColumn.get_Properties(), OUString( "Autoincrement" ), getBOOL( rValue ) ); + break; + + case PROPERTY_ID_IM001: + case PROPERTY_ID_DESCRIPTION: + pAdoPropertyName = "Description"; + break; + + case PROPERTY_ID_DEFAULTVALUE: + pAdoPropertyName = "Default"; + break; + } + + if ( pAdoPropertyName ) + OTools::putValue( m_aColumn.get_Properties(), OUString::createFromAscii( pAdoPropertyName ), getString( rValue ) ); + } + OColumn_ADO::setFastPropertyValue_NoBroadcast(nHandle,rValue); +} + +void OAdoColumn::fillPropertyValues() +{ + if(m_aColumn.IsValid()) + { + m_IsAscending = m_aColumn.get_SortOrder() == adSortAscending; + m_ReferencedColumn = m_aColumn.get_RelatedColumn(); + m_Name = m_aColumn.get_Name(); + m_Precision = m_aColumn.get_Precision(); + m_Scale = m_aColumn.get_NumericScale(); + m_IsNullable = ((m_aColumn.get_Attributes() & adColNullable) == adColNullable) ? ColumnValue::NULLABLE : ColumnValue::NO_NULLS; + + DataTypeEnum eType = m_aColumn.get_Type(); + m_IsCurrency = (eType == adCurrency); + if ( m_IsCurrency && !m_Scale) + m_Scale = 4; + m_Type = ADOS::MapADOType2Jdbc(eType); + + bool bForceTo = true; + const OTypeInfoMap* pTypeInfoMap = m_pConnection->getTypeInfo(); + const OExtendedTypeInfo* pTypeInfo = OConnection::getTypeInfoFromType(*m_pConnection->getTypeInfo(),eType,OUString(),m_Precision,m_Scale,bForceTo); + if ( pTypeInfo ) + m_TypeName = pTypeInfo->aSimpleType.aTypeName; + else if ( eType == adVarBinary && ADOS::isJetEngine(m_pConnection->getEngineType()) ) + { + ::comphelper::UStringMixEqual aCase(false); + OTypeInfoMap::const_iterator aFind = std::find_if(pTypeInfoMap->begin(), pTypeInfoMap->end(), + [&aCase] (const OTypeInfoMap::value_type& typeInfo) { + return aCase(typeInfo.second->getDBName(), OUString("VarBinary")); + }); + + if ( aFind != pTypeInfoMap->end() ) // change column type if necessary + { + eType = aFind->first; + pTypeInfo = aFind->second; + } + + if ( !pTypeInfo ) + { + pTypeInfo = OConnection::getTypeInfoFromType(*m_pConnection->getTypeInfo(),adBinary,OUString(),m_Precision,m_Scale,bForceTo); + eType = adBinary; + } + + if ( pTypeInfo ) + { + m_TypeName = pTypeInfo->aSimpleType.aTypeName; + m_Type = ADOS::MapADOType2Jdbc(eType); + } + } + + + // fill some specific props + { + WpADOProperties aProps( m_aColumn.get_Properties() ); + + if ( aProps.IsValid() ) + { + m_IsAutoIncrement = OTools::getValue( aProps, OUString("Autoincrement") ).getBool(); + + m_Description = OTools::getValue( aProps, OUString("Description") ).getString(); + + m_DefaultValue = OTools::getValue( aProps, OUString("Default") ).getString(); + } + } + } +} + +WpADOColumn OAdoColumn::getColumnImpl() const +{ + return m_aColumn; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AColumns.cxx b/connectivity/source/drivers/ado/AColumns.cxx new file mode 100644 index 000000000..e9dc7720f --- /dev/null +++ b/connectivity/source/drivers/ado/AColumns.cxx @@ -0,0 +1,130 @@ +/* -*- 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 <ado/AColumns.hxx> +#include <ado/AColumn.hxx> +#include <ado/AConnection.hxx> +#include <ado/Awrapado.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <comphelper/property.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <algorithm> +#include <strings.hrc> + +using namespace connectivity::ado; +using namespace connectivity; +using namespace comphelper; +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::container; + +sdbcx::ObjectType OColumns::createObject(const OUString& _rName) +{ + return new OAdoColumn(isCaseSensitive(),m_pConnection,m_aCollection.GetItem(_rName)); +} + + +void OColumns::impl_refresh() +{ + m_aCollection.Refresh(); +} + +Reference< XPropertySet > OColumns::createDescriptor() +{ + return new OAdoColumn(isCaseSensitive(),m_pConnection); +} + +// XAppend +sdbcx::ObjectType OColumns::appendObject( const OUString&, const Reference< XPropertySet >& descriptor ) +{ + OAdoColumn* pColumn = getUnoTunnelImplementation<OAdoColumn>( descriptor ); + Reference< XPropertySet > xColumn; + if ( pColumn == nullptr ) + { + // m_pConnection->throwGenericSQLException( STR_INVALID_COLUMN_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + pColumn = new OAdoColumn(isCaseSensitive(),m_pConnection); + xColumn = pColumn; + ::comphelper::copyProperties(descriptor,xColumn); + } + + WpADOColumn aColumn = pColumn->getColumnImpl(); + +#if OSL_DEBUG_LEVEL > 0 + sal_Int32 nPrecision; + sal_Int32 nScale; + sal_Int32 nType; + nPrecision = aColumn.get_Precision(); + nScale = aColumn.get_NumericScale(); + nType = ADOS::MapADOType2Jdbc(aColumn.get_Type()); +#endif + + OUString sTypeName; + pColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sTypeName; + + const OTypeInfoMap* pTypeInfoMap = m_pConnection->getTypeInfo(); + ::comphelper::UStringMixEqual aCase(false); + // search for typeinfo where the typename is equal sTypeName + OTypeInfoMap::const_iterator aFind = std::find_if(pTypeInfoMap->begin(), pTypeInfoMap->end(), + [&aCase, &sTypeName] (const OTypeInfoMap::value_type& typeInfo) { + return aCase(typeInfo.second->getDBName(), sTypeName); + }); + + if ( aFind != pTypeInfoMap->end() ) // change column type if necessary + aColumn.put_Type(aFind->first); + + if ( SUCCEEDED(static_cast<ADOColumns*>(m_aCollection)->Append(OLEVariant(aColumn.get_Name()),aColumn.get_Type(),aColumn.get_DefinedSize())) ) + { + WpADOColumn aAddedColumn = m_aCollection.GetItem(OLEVariant(aColumn.get_Name())); + if ( aAddedColumn.IsValid() ) + { + bool bAutoIncrement = false; + pColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement; + if ( bAutoIncrement ) + OTools::putValue( aAddedColumn.get_Properties(), OUString("Autoincrement"), bAutoIncrement ); + + if ( aFind != pTypeInfoMap->end() && aColumn.get_Type() != aAddedColumn.get_Type() ) // change column type if necessary + aColumn.put_Type(aFind->first); + aAddedColumn.put_Precision(aColumn.get_Precision()); + aAddedColumn.put_NumericScale(aColumn.get_NumericScale()); + aAddedColumn.put_Attributes(aColumn.get_Attributes()); + aAddedColumn.put_SortOrder(aColumn.get_SortOrder()); + aAddedColumn.put_RelatedColumn(aColumn.get_RelatedColumn()); + } + } + ADOS::ThrowException(*m_pConnection->getConnection(),static_cast<XTypeProvider*>(this)); + + return new OAdoColumn(isCaseSensitive(),m_pConnection,pColumn->getColumnImpl()); +} + +// XDrop +void OColumns::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + if(!m_aCollection.Delete(_sElementName)) + ADOS::ThrowException(*m_pConnection->getConnection(),static_cast<XTypeProvider*>(this)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AConnection.cxx b/connectivity/source/drivers/ado/AConnection.cxx new file mode 100644 index 000000000..c9251a9be --- /dev/null +++ b/connectivity/source/drivers/ado/AConnection.cxx @@ -0,0 +1,587 @@ +/* -*- 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 <ado/AConnection.hxx> +#include <ado/ADatabaseMetaData.hxx> +#include <ado/ADriver.hxx> +#include <ado/AStatement.hxx> +#include <ado/ACallableStatement.hxx> +#include <ado/APreparedStatement.hxx> +#include <ado/ACatalog.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <connectivity/dbexception.hxx> +#include <osl/file.hxx> +#include <strings.hrc> + +using namespace dbtools; +using namespace connectivity::ado; +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::sdbcx; + + +IMPLEMENT_SERVICE_INFO(OConnection,"com.sun.star.sdbcx.AConnection","com.sun.star.sdbc.Connection"); + +OConnection::OConnection(ODriver* _pDriver) + : m_xCatalog(nullptr), + m_pDriver(_pDriver), + m_pAdoConnection(nullptr), + m_pCatalog(nullptr), + m_nEngineType(0), + m_bClosed(false), + m_bAutocommit(true) +{ + osl_atomic_increment( &m_refCount ); + + IClassFactory2* pIUnknown = nullptr; + HRESULT hr; + hr = CoGetClassObject( ADOS::CLSID_ADOCONNECTION_21, + CLSCTX_INPROC_SERVER, + nullptr, + IID_IClassFactory2, + reinterpret_cast<void**>(&pIUnknown) ); + + if( !FAILED( hr ) ) + { + ADOConnection *pCon = nullptr; + IUnknown *pOuter = nullptr; + hr = pIUnknown->CreateInstanceLic( pOuter, + nullptr, + ADOS::IID_ADOCONNECTION_21, + ADOS::GetKeyStr().asBSTR(), + reinterpret_cast<void**>(&pCon)); + + if( !FAILED( hr ) ) + { + OSL_ENSURE( pCon, "OConnection::OConnection: invalid ADO object!" ); + + m_pAdoConnection = new WpADOConnection( pCon ); + // CreateInstanceLic returned an object which was already acquired + pCon->Release( ); + + } + + // Class Factory is no longer needed + pIUnknown->Release(); + } + + osl_atomic_decrement( &m_refCount ); +} + +OConnection::~OConnection() +{ +} + +void OConnection::construct(const OUString& url,const Sequence< PropertyValue >& info) +{ + osl_atomic_increment( &m_refCount ); + + setConnectionInfo(info); + + sal_Int32 nLen = url.indexOf(':'); + nLen = url.indexOf(':',nLen+1); + OUString aDSN(url.copy(nLen+1)),aUID,aPWD; + if ( aDSN.startsWith("access:") ) + aDSN = aDSN.copy(7); + + sal_Int32 nTimeout = 20; + const PropertyValue *pIter = info.getConstArray(); + const PropertyValue *pEnd = pIter + info.getLength(); + for(;pIter != pEnd;++pIter) + { + if(pIter->Name == "Timeout") + pIter->Value >>= nTimeout; + else if(pIter->Name == "user") + pIter->Value >>= aUID; + else if(pIter->Name == "password") + pIter->Value >>= aPWD; + } + try + { + if(m_pAdoConnection) + { + if(m_pAdoConnection->Open(aDSN,aUID,aPWD,adConnectUnspecified)) + m_pAdoConnection->PutCommandTimeout(nTimeout); + else + ADOS::ThrowException(*m_pAdoConnection,*this); + if(m_pAdoConnection->get_State() != adStateOpen) + throwGenericSQLException( STR_NO_CONNECTION,*this ); + + WpADOProperties aProps = m_pAdoConnection->get_Properties(); + if(aProps.IsValid()) + { + OTools::putValue(aProps,OUString("Jet OLEDB:ODBC Parsing"),true); + OLEVariant aVar(OTools::getValue(aProps,OUString("Jet OLEDB:Engine Type"))); + if(!aVar.isNull() && !aVar.isEmpty()) + m_nEngineType = aVar.getInt32(); + } + buildTypeInfo(); + //bErg = TRUE; + } + else + ::dbtools::throwFunctionSequenceException(*this); + + } + catch(const Exception& ) + { + osl_atomic_decrement( &m_refCount ); + throw; + } + osl_atomic_decrement( &m_refCount ); +} + +Reference< XStatement > SAL_CALL OConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + OStatement* pStmt = new OStatement(this); + Reference< XStatement > xStmt = pStmt; + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return pStmt; +} + +Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OPreparedStatement* pStmt = new OPreparedStatement(this, sql); + Reference< XPreparedStatement > xPStmt = pStmt; + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return xPStmt; +} + +Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OCallableStatement* pStmt = new OCallableStatement(this, sql); + Reference< XPreparedStatement > xPStmt = pStmt; + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return xPStmt; +} + +OUString SAL_CALL OConnection::nativeSQL( const OUString& _sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OUString sql = _sql; + WpADOProperties aProps = m_pAdoConnection->get_Properties(); + if(aProps.IsValid()) + { + OTools::putValue(aProps,OUString("Jet OLEDB:ODBC Parsing"),true); + WpADOCommand aCommand; + aCommand.Create(); + aCommand.put_ActiveConnection(static_cast<IDispatch*>(*m_pAdoConnection)); + aCommand.put_CommandText(sql); + sql = aCommand.get_CommandText(); + } + + return sql; +} + +void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + m_bAutocommit = autoCommit; + if(!autoCommit) + m_pAdoConnection->BeginTrans(); + else + m_pAdoConnection->RollbackTrans(); +} + +sal_Bool SAL_CALL OConnection::getAutoCommit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + return m_bAutocommit; +} + +void SAL_CALL OConnection::commit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + m_pAdoConnection->CommitTrans(); +} + +void SAL_CALL OConnection::rollback( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + m_pAdoConnection->RollbackTrans(); +} + +sal_Bool SAL_CALL OConnection::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return OConnection_BASE::rBHelper.bDisposed && !m_pAdoConnection->get_State(); +} + +Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new ODatabaseMetaData(this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + m_pAdoConnection->put_Mode(readOnly ? adModeRead : adModeReadWrite); + ADOS::ThrowException(*m_pAdoConnection,*this); +} + +sal_Bool SAL_CALL OConnection::isReadOnly( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + return m_pAdoConnection->get_Mode() == adModeRead; +} + +void SAL_CALL OConnection::setCatalog( const OUString& catalog ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + m_pAdoConnection->PutDefaultDatabase(catalog); + ADOS::ThrowException(*m_pAdoConnection,*this); +} + +OUString SAL_CALL OConnection::getCatalog( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + return m_pAdoConnection->GetDefaultDatabase(); +} + +void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 level ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + IsolationLevelEnum eIso; + switch(level) + { + case TransactionIsolation::NONE: + eIso = adXactUnspecified; + break; + case TransactionIsolation::READ_UNCOMMITTED: + eIso = adXactReadUncommitted; + break; + case TransactionIsolation::READ_COMMITTED: + eIso = adXactReadCommitted; + break; + case TransactionIsolation::REPEATABLE_READ: + eIso = adXactRepeatableRead; + break; + case TransactionIsolation::SERIALIZABLE: + eIso = adXactSerializable; + break; + default: + OSL_FAIL("OConnection::setTransactionIsolation invalid level"); + return; + } + m_pAdoConnection->put_IsolationLevel(eIso); + ADOS::ThrowException(*m_pAdoConnection,*this); +} + +sal_Int32 SAL_CALL OConnection::getTransactionIsolation( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + sal_Int32 nRet = 0; + switch(m_pAdoConnection->get_IsolationLevel()) + { + case adXactUnspecified: + nRet = TransactionIsolation::NONE; + break; + case adXactReadUncommitted: + nRet = TransactionIsolation::READ_UNCOMMITTED; + break; + case adXactReadCommitted: + nRet = TransactionIsolation::READ_COMMITTED; + break; + case adXactRepeatableRead: + nRet = TransactionIsolation::REPEATABLE_READ; + break; + case adXactSerializable: + nRet = TransactionIsolation::SERIALIZABLE; + break; + default: + OSL_FAIL("OConnection::setTransactionIsolation invalid level"); + } + ADOS::ThrowException(*m_pAdoConnection,*this); + return nRet; +} + +Reference< css::container::XNameAccess > SAL_CALL OConnection::getTypeMap( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + return nullptr; +} + +void SAL_CALL OConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this ); +} + +// XCloseable +void SAL_CALL OConnection::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + } + dispose(); +} + +// XWarningsSupplier +Any SAL_CALL OConnection::getWarnings( ) +{ + return Any(); +} + +void SAL_CALL OConnection::clearWarnings( ) +{ +} + +void OConnection::buildTypeInfo() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ADORecordset *pRecordset = m_pAdoConnection->getTypeInfo(); + if ( pRecordset ) + { + pRecordset->AddRef(); + VARIANT_BOOL bIsAtBOF; + pRecordset->get_BOF(&bIsAtBOF); + + bool bOk = true; + if ( bIsAtBOF == VARIANT_TRUE ) + bOk = SUCCEEDED(pRecordset->MoveNext()); + + if ( bOk ) + { + // HACK for access + static const char s_sVarChar[] = "VarChar"; + do + { + sal_Int32 nPos = 1; + OExtendedTypeInfo* aInfo = new OExtendedTypeInfo; + aInfo->aSimpleType.aTypeName = ADOS::getField(pRecordset,nPos++).get_Value().getString(); + aInfo->eType = static_cast<DataTypeEnum>(ADOS::getField(pRecordset,nPos++).get_Value().getInt32()); + if ( aInfo->eType == adWChar && aInfo->aSimpleType.aTypeName == s_sVarChar ) + aInfo->eType = adVarWChar; + aInfo->aSimpleType.nType = static_cast<sal_Int16>(ADOS::MapADOType2Jdbc(aInfo->eType)); + aInfo->aSimpleType.nPrecision = ADOS::getField(pRecordset,nPos++).get_Value().getInt32(); + nPos++; // aLiteralPrefix + nPos++; // aLiteralSuffix + nPos++; // aCreateParams + nPos++; // bNullable + nPos++; // bCaseSensitive + nPos++; // nSearchType + nPos++; // bUnsigned + nPos++; // bCurrency + nPos++; // bAutoIncrement + aInfo->aSimpleType.aLocalTypeName = ADOS::getField(pRecordset,nPos++).get_Value().getString(); + nPos++; // nMinimumScale + aInfo->aSimpleType.nMaximumScale = ADOS::getField(pRecordset,nPos++).get_Value().getInt16(); + if ( adCurrency == aInfo->eType && !aInfo->aSimpleType.nMaximumScale) + { + aInfo->aSimpleType.nMaximumScale = 4; + } + nPos++; // nNumPrecRadix + // Now that we have the type info, save it + // in the Hashtable if we don't already have an + // entry for this SQL type. + + m_aTypeInfo.emplace(aInfo->eType,aInfo); + } + while ( SUCCEEDED(pRecordset->MoveNext()) ); + } + pRecordset->Release(); + } +} + +void OConnection::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + OConnection_BASE::disposing(); + + m_bClosed = true; + m_xMetaData = css::uno::WeakReference< css::sdbc::XDatabaseMetaData>(); + m_xCatalog = css::uno::WeakReference< css::sdbcx::XTablesSupplier>(); + m_pDriver = nullptr; + + m_pAdoConnection->Close(); + + for (auto& rEntry : m_aTypeInfo) + delete rEntry.second; + + m_aTypeInfo.clear(); + + delete m_pAdoConnection; + m_pAdoConnection = nullptr; +} + +sal_Int64 SAL_CALL OConnection::getSomething( const css::uno::Sequence< sal_Int8 >& rId ) +{ + return isUnoTunnelId<OConnection>(rId) + ? + reinterpret_cast< sal_Int64 >( this ) + : + OConnection_BASE::getSomething(rId); +} + +Sequence< sal_Int8 > OConnection::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +const OExtendedTypeInfo* OConnection::getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo, + DataTypeEnum _nType, + const OUString& _sTypeName, + sal_Int32 _nPrecision, + sal_Int32 _nScale, + bool& _brForceToType) +{ + const OExtendedTypeInfo* pTypeInfo = nullptr; + _brForceToType = false; + // search for type + std::pair<OTypeInfoMap::const_iterator, OTypeInfoMap::const_iterator> aPair = _rTypeInfo.equal_range(_nType); + OTypeInfoMap::const_iterator aIter = aPair.first; + if(aIter != _rTypeInfo.end()) // compare with end is correct here + { + for(;aIter != aPair.second;++aIter) + { + // search the best matching type + OExtendedTypeInfo* pInfo = aIter->second; + if ( ( !_sTypeName.getLength() + || (pInfo->aSimpleType.aTypeName.equalsIgnoreAsciiCase(_sTypeName)) + ) + && (pInfo->aSimpleType.nPrecision >= _nPrecision) + && (pInfo->aSimpleType.nMaximumScale >= _nScale) + + ) + break; + } + + if (aIter == aPair.second) + { + for(aIter = aPair.first; aIter != aPair.second; ++aIter) + { + // search the best matching type (now comparing the local names) + if ( (aIter->second->aSimpleType.aLocalTypeName.equalsIgnoreAsciiCase(_sTypeName)) + && (aIter->second->aSimpleType.nPrecision >= _nPrecision) + && (aIter->second->aSimpleType.nMaximumScale >= _nScale) + ) + { +// we can not assert here because we could be in d&d +/* + OSL_FAIL(( OString("getTypeInfoFromType: assuming column type ") + += OString(aIter->second->aTypeName.getStr(), aIter->second->aTypeName.getLength(), osl_getThreadTextEncoding()) + += OString("\" (expected type name ") + += OString(_sTypeName.getStr(), _sTypeName.getLength(), osl_getThreadTextEncoding()) + += OString(" matches the type's local name).")).getStr()); +*/ + break; + } + } + } + + if (aIter == aPair.second) + { // no match for the names, no match for the local names + // -> drop the precision and the scale restriction, accept any type with the property + // type id (nType) + + // we can not assert here because we could be in d&d + pTypeInfo = aPair.first->second; + _brForceToType = true; + } + else + pTypeInfo = aIter->second; + } + else if ( _sTypeName.getLength() ) + { + ::comphelper::UStringMixEqual aCase(false); + // search for typeinfo where the typename is equal _sTypeName + OTypeInfoMap::const_iterator aFind = std::find_if(_rTypeInfo.begin(), _rTypeInfo.end(), + [&aCase, &_sTypeName] (const OTypeInfoMap::value_type& typeInfo) { + return aCase(typeInfo.second->getDBName(), _sTypeName); + }); + + if(aFind != _rTypeInfo.end()) + pTypeInfo = aFind->second; + } + +// we can not assert here because we could be in d&d +// OSL_ENSURE(pTypeInfo, "getTypeInfoFromType: no type info found for this type!"); + return pTypeInfo; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ADatabaseMetaData.cxx b/connectivity/source/drivers/ado/ADatabaseMetaData.cxx new file mode 100644 index 000000000..8e46761e8 --- /dev/null +++ b/connectivity/source/drivers/ado/ADatabaseMetaData.cxx @@ -0,0 +1,1073 @@ +/* -*- 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 <ado/ADatabaseMetaData.hxx> +#include <ado/ADatabaseMetaDataResultSet.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <ado/AConnection.hxx> +#include <ado/adoimp.hxx> +#include <FDatabaseMetaDataResultSet.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> + +using namespace ::comphelper; + +using namespace connectivity; +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + + +ODatabaseMetaData::ODatabaseMetaData(OConnection* _pCon) + : ::connectivity::ODatabaseMetaDataBase(_pCon,_pCon->getConnectionInfo()) + ,m_pADOConnection(_pCon->getConnection()) + ,m_pConnection(_pCon) +{ +} + +sal_Int32 ODatabaseMetaData::getInt32Property(const OUString& _aProperty) +{ + connectivity::ado::WpADOProperties aProps(m_pADOConnection->get_Properties()); + // ADOS::ThrowException(*m_pADOConnection,*this); + OSL_ENSURE(aProps.IsValid(),"There are no properties at the connection"); + ADO_PROP(_aProperty); + sal_Int32 nValue(0); + if(!aVar.isNull() && !aVar.isEmpty()) + nValue = aVar.getInt32(); + return nValue; +} + + +bool ODatabaseMetaData::getBoolProperty(const OUString& _aProperty) +{ + connectivity::ado::WpADOProperties aProps(m_pADOConnection->get_Properties()); + ADOS::ThrowException(*m_pADOConnection,*this); + OSL_ENSURE(aProps.IsValid(),"There are no properties at the connection"); + ADO_PROP(_aProperty); + return !aVar.isNull() && !aVar.isEmpty() && aVar.getBool(); +} + +OUString ODatabaseMetaData::getStringProperty(const OUString& _aProperty) +{ + connectivity::ado::WpADOProperties aProps(m_pADOConnection->get_Properties()); + ADOS::ThrowException(*m_pADOConnection,*this); + OSL_ENSURE(aProps.IsValid(),"There are no properties at the connection"); + + ADO_PROP(_aProperty); + OUString aValue; + if(!aVar.isNull() && !aVar.isEmpty() && aVar.getType() == VT_BSTR) + aValue = aVar.getString(); + + return aValue; +} + +Reference< XResultSet > ODatabaseMetaData::impl_getTypeInfo_throw( ) +{ + ADORecordset *pRecordset = m_pADOConnection->getTypeInfo(); + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setTypeInfoMap(ADOS::isJetEngine(m_pConnection->getEngineType())); + Reference< XResultSet > xRef = pResult; + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCatalogs( ) +{ + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + ADORecordset *pRecordset = nullptr; + m_pADOConnection->OpenSchema(adSchemaCatalogs,vtEmpty,vtEmpty,&pRecordset); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setCatalogsMap(); + xRef = pResult; + + return xRef; +} + +OUString ODatabaseMetaData::impl_getCatalogSeparator_throw( ) +{ + return getLiteral(DBLITERAL_CATALOG_SEPARATOR); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSchemas( ) +{ + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + ADORecordset *pRecordset = nullptr; + m_pADOConnection->OpenSchema(adSchemaSchemata,vtEmpty,vtEmpty,&pRecordset); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setSchemasMap(); + xRef = pResult; + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumnPrivileges( + const Any& catalog, const OUString& schema, const OUString& table, + const OUString& columnNamePattern ) +{ + ADORecordset *pRecordset = m_pADOConnection->getColumnPrivileges(catalog,schema,table,columnNamePattern); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setColumnPrivilegesMap(); + xRef = pResult; + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( + const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + ADORecordset *pRecordset = m_pADOConnection->getColumns(catalog,schemaPattern,tableNamePattern,columnNamePattern); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setColumnsMap(); + xRef = pResult; + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables( + const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, const Sequence< OUString >& types ) +{ + ADORecordset *pRecordset = m_pADOConnection->getTables(catalog,schemaPattern,tableNamePattern,types); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setTablesMap(); + xRef = pResult; + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedureColumns( + const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern, const OUString& columnNamePattern ) +{ + ADORecordset *pRecordset = m_pADOConnection->getProcedureColumns(catalog,schemaPattern,procedureNamePattern,columnNamePattern); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setProcedureColumnsMap(); + xRef = pResult; + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedures( + const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern ) +{ + // Create elements used in the array + ADORecordset *pRecordset = m_pADOConnection->getProcedures(catalog,schemaPattern,procedureNamePattern); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setProceduresMap(); + xRef = pResult; + + return xRef; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return getMaxSize(DBLITERAL_BINARY_LITERAL); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize( ) +{ + return getInt32Property("Maximum Row Size"); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength( ) +{ + return getMaxSize(DBLITERAL_CATALOG_NAME); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength( ) +{ + return getMaxSize(DBLITERAL_CHAR_LITERAL); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength( ) +{ + return getMaxSize(DBLITERAL_COLUMN_NAME); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength( ) +{ + return getMaxSize(DBLITERAL_CURSOR_NAME); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections( ) +{ + return getInt32Property("Active Sessions"); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable( ) +{ + return getInt32Property("Max Columns in Table"); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength( ) +{ + return getMaxSize(DBLITERAL_TEXT_COMMAND); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength( ) +{ + return getMaxSize(DBLITERAL_TABLE_NAME); +} + +sal_Int32 ODatabaseMetaData::impl_getMaxTablesInSelect_throw( ) +{ + return getInt32Property("Maximum Tables in SELECT"); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getExportedKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + ADORecordset *pRecordset = m_pADOConnection->getExportedKeys(catalog,schema,table); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setCrossReferenceMap(); + xRef = pResult; + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getImportedKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + ADORecordset *pRecordset = m_pADOConnection->getImportedKeys(catalog,schema,table); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setCrossReferenceMap(); + xRef = pResult; + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPrimaryKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + ADORecordset *pRecordset = m_pADOConnection->getPrimaryKeys(catalog,schema,table); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setPrimaryKeysMap(); + xRef = pResult; + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo( + const Any& catalog, const OUString& schema, const OUString& table, + sal_Bool unique, sal_Bool approximate ) +{ + ADORecordset *pRecordset = m_pADOConnection->getIndexInfo(catalog,schema,table,unique,approximate); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setIndexInfoMap(); + xRef = pResult; + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges( + const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) +{ + Reference< XResultSet > xRef; + if(!ADOS::isJetEngine(m_pConnection->getEngineType())) + { // the jet provider doesn't support this method + // Create elements used in the array + + ADORecordset *pRecordset = m_pADOConnection->getTablePrivileges(catalog,schemaPattern,tableNamePattern); + ADOS::ThrowException(*m_pADOConnection,*this); + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setTablePrivilegesMap(); + xRef = pResult; + } + else + { + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTablePrivileges); + xRef = pResult; + ::connectivity::ODatabaseMetaDataResultSet::ORows aRows; + ::connectivity::ODatabaseMetaDataResultSet::ORow aRow(8); + aRows.reserve(8); + + aRow[0] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[1] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[2] = new ::connectivity::ORowSetValueDecorator(tableNamePattern); + aRow[3] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[4] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[5] = new ::connectivity::ORowSetValueDecorator(getUserName()); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getSelectValue(); + aRow[7] = new ::connectivity::ORowSetValueDecorator(OUString("NO")); + + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getInsertValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getDeleteValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getUpdateValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getCreateValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getReadValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getAlterValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getDropValue(); + aRows.push_back(aRow); + pResult->setRows(aRows); + } + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCrossReference( + const Any& primaryCatalog, const OUString& primarySchema, + const OUString& primaryTable, const Any& foreignCatalog, + const OUString& foreignSchema, const OUString& foreignTable ) +{ + ADORecordset *pRecordset = m_pADOConnection->getCrossReference(primaryCatalog,primarySchema,primaryTable,foreignCatalog,foreignSchema,foreignTable); + ADOS::ThrowException(*m_pADOConnection,*this); + + Reference< XResultSet > xRef; + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(pRecordset); + pResult->setCrossReferenceMap(); + xRef = pResult; + + return xRef; +} + +sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + return getBoolProperty("Maximum Row Size Includes BLOB"); +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_LOWER) == DBPROPVAL_IC_LOWER ; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_LOWER) == DBPROPVAL_IC_LOWER ; +} + +bool ODatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( ) +{ + return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_MIXED) == DBPROPVAL_IC_MIXED ; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_MIXED) == DBPROPVAL_IC_MIXED ; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_UPPER) == DBPROPVAL_IC_UPPER ; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_UPPER) == DBPROPVAL_IC_UPPER ; +} + +bool ODatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( ) +{ + return true; +} + +bool ODatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( ) +{ + return true; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( ) +{ + return getInt32Property("Maximum Index Size"); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( ) +{ + return getInt32Property("NULL Concatenation Behavior") == DBPROPVAL_CB_NON_NULL; +} + +OUString SAL_CALL ODatabaseMetaData::getCatalogTerm( ) +{ + return getStringProperty("Catalog Term"); +} + +OUString ODatabaseMetaData::impl_getIdentifierQuoteString_throw( ) +{ + return getLiteral(DBLITERAL_QUOTE_PREFIX); + +} + +OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + return isCapable(DBLITERAL_CORRELATION_NAME); +} + +bool ODatabaseMetaData::impl_isCatalogAtStart_throw( ) +{ + return getInt32Property("Catalog Location") == DBPROPVAL_CL_START; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + return getInt32Property("Transaction DDL") == DBPROPVAL_TC_DDL_IGNORE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + return getInt32Property("Transaction DDL") == DBPROPVAL_TC_DDL_COMMIT; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + return getInt32Property("Transaction DDL") == DBPROPVAL_TC_DML; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + return getInt32Property("Transaction DDL") == DBPROPVAL_TC_ALL; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + return getInt32Property("Prepare Abort Behavior") == DBPROPVAL_CB_PRESERVE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + return getInt32Property("Prepare Commit Behavior") == DBPROPVAL_CB_PRESERVE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + return (getInt32Property("Isolation Retention") & DBPROPVAL_TR_COMMIT) == DBPROPVAL_TR_COMMIT; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + return (getInt32Property("Isolation Retention") & DBPROPVAL_TR_ABORT) == DBPROPVAL_TR_ABORT; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level ) +{ + bool bValue(false); + + sal_Int32 nTxn = getInt32Property("Isolation Levels"); + if(level == TransactionIsolation::NONE) + bValue = true; + else if(level == TransactionIsolation::READ_UNCOMMITTED) + bValue = (nTxn & DBPROPVAL_TI_READUNCOMMITTED) == DBPROPVAL_TI_READUNCOMMITTED; + else if(level == TransactionIsolation::READ_COMMITTED) + bValue = (nTxn & DBPROPVAL_TI_READCOMMITTED) == DBPROPVAL_TI_READCOMMITTED; + else if(level == TransactionIsolation::REPEATABLE_READ) + bValue = (nTxn & DBPROPVAL_TI_REPEATABLEREAD) == DBPROPVAL_TI_REPEATABLEREAD; + else if(level == TransactionIsolation::SERIALIZABLE) + bValue = (nTxn & DBPROPVAL_TI_SERIALIZABLE) == DBPROPVAL_TI_SERIALIZABLE; + + return bValue; +} + +bool ODatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( ) +{ + return (getInt32Property("Schema Usage") & DBPROPVAL_SU_DML_STATEMENTS) == DBPROPVAL_SU_DML_STATEMENTS; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( ) +{ + sal_Int32 nProp = getInt32Property("SQL Support"); + return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ANSI92_FULL) == DBPROPVAL_SQL_ANSI92_FULL); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + sal_Int32 nProp = getInt32Property("SQL Support"); + return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ANSI92_ENTRY) == DBPROPVAL_SQL_ANSI92_ENTRY); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + sal_Int32 nProp = getInt32Property("SQL Support"); + return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ANSI89_IEF) == DBPROPVAL_SQL_ANSI89_IEF); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + return (getInt32Property("Schema Usage") & DBPROPVAL_SU_INDEX_DEFINITION) == DBPROPVAL_SU_INDEX_DEFINITION; +} + +bool ODatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( ) +{ + return (getInt32Property("Schema Usage") & DBPROPVAL_SU_TABLE_DEFINITION) == DBPROPVAL_SU_TABLE_DEFINITION; +} + +bool ODatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins( ) +{ + if ( ADOS::isJetEngine(m_pConnection->getEngineType()) ) + return true; + return getBoolProperty("Outer Join Capabilities"); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( ) +{ + return new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTableTypes); +} + +sal_Int32 ODatabaseMetaData::impl_getMaxStatements_throw( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( ) +{ + return getMaxSize(DBLITERAL_PROCEDURE_NAME); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength( ) +{ + return getMaxSize(DBLITERAL_SCHEMA_NAME); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions( ) +{ + return getInt32Property("Transaction DDL") == DBPROPVAL_TC_NONE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( ) +{ + return getBoolProperty("Read-Only Data Source"); +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( ) +{ + return getInt32Property("NULL Concatenation Behavior") == DBPROPVAL_CB_NULL; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing( ) +{ + return isCapable(DBLITERAL_COLUMN_ALIAS); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames( ) +{ + return isCapable(DBLITERAL_CORRELATION_NAME); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert( sal_Int32 /*fromType*/, sal_Int32 /*toType*/ ) +{ + return getBoolProperty("Rowset Conversions on Command"); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + return getBoolProperty("ORDER BY Columns in Select List"); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( ) +{ + return getInt32Property("GROUP BY Support") != DBPROPVAL_GB_NOT_SUPPORTED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + return getInt32Property("GROUP BY Support") != DBPROPVAL_GB_CONTAINS_SELECT; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( ) +{ + return getInt32Property("GROUP BY Support") == DBPROPVAL_GB_NO_RELATION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( ) +{ + return isCapable(DBLITERAL_ESCAPE_PERCENT); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( ) +{ + return getBoolProperty("ORDER BY Columns in Select List"); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_MIXED) == DBPROPVAL_IC_MIXED; +} + +bool ODatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( ) +{ + return (getInt32Property("Identifier Case Sensitivity") & DBPROPVAL_IC_MIXED) == DBPROPVAL_IC_MIXED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( ) +{ + return (getInt32Property("NULL Collation Order") & DBPROPVAL_NC_END) == DBPROPVAL_NC_END; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( ) +{ + return (getInt32Property("NULL Collation Order") & DBPROPVAL_NC_START) == DBPROPVAL_NC_START; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( ) +{ + return (getInt32Property("NULL Collation Order") & DBPROPVAL_NC_HIGH) == DBPROPVAL_NC_HIGH; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( ) +{ + return (getInt32Property("NULL Collation Order") & DBPROPVAL_NC_LOW) == DBPROPVAL_NC_LOW; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + return (getInt32Property("Schema Usage") & DBPROPVAL_SU_PRIVILEGE_DEFINITION) == DBPROPVAL_SU_PRIVILEGE_DEFINITION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_CORRELATEDSUBQUERIES) == DBPROPVAL_SQ_CORRELATEDSUBQUERIES; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_COMPARISON) == DBPROPVAL_SQ_COMPARISON; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( ) +{ + return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_EXISTS) == DBPROPVAL_SQ_EXISTS; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( ) +{ + return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_IN) == DBPROPVAL_SQ_IN; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + return (getInt32Property("Subquery Support") & DBPROPVAL_SQ_QUANTIFIED) == DBPROPVAL_SQ_QUANTIFIED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + sal_Int32 nProp = getInt32Property("SQL Support"); + return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ANSI92_INTERMEDIATE) == DBPROPVAL_SQL_ANSI92_INTERMEDIATE); +} + +OUString SAL_CALL ODatabaseMetaData::getURL( ) +{ + return "sdbc:ado:"+ m_pADOConnection->GetConnectionString(); +} + +OUString SAL_CALL ODatabaseMetaData::getUserName( ) +{ + return getStringProperty("User Name"); +} + +OUString SAL_CALL ODatabaseMetaData::getDriverName( ) +{ + return getStringProperty("Provider Friendly Name"); +} + +OUString SAL_CALL ODatabaseMetaData::getDriverVersion( ) +{ + return getStringProperty("Provider Version"); +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( ) +{ + return getStringProperty("DBMS Version"); +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( ) +{ + return getStringProperty("DBMS Name"); +} + +OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( ) +{ + return getStringProperty("Procedure Term"); +} + +OUString SAL_CALL ODatabaseMetaData::getSchemaTerm( ) +{ + return getStringProperty("Schema Term"); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation( ) +{ + sal_Int32 nRet = TransactionIsolation::NONE; + switch(m_pADOConnection->get_IsolationLevel()) + { + case adXactReadCommitted: + nRet = TransactionIsolation::READ_COMMITTED; + break; + case adXactRepeatableRead: + nRet = TransactionIsolation::REPEATABLE_READ; + break; + case adXactSerializable: + nRet = TransactionIsolation::SERIALIZABLE; + break; + case adXactReadUncommitted: + nRet = TransactionIsolation::READ_UNCOMMITTED; + break; + default: + ; + } + return nRet; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( ) +{ + return 0; +} + +OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( ) +{ + ADORecordset *pRecordset = nullptr; + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + m_pADOConnection->OpenSchema(adSchemaDBInfoKeywords,vtEmpty,vtEmpty,&pRecordset); + OSL_ENSURE(pRecordset,"getSQLKeywords: no resultset!"); + ADOS::ThrowException(*m_pADOConnection,*this); + if ( pRecordset ) + { + WpADORecordset aRecordset(pRecordset); + + aRecordset.MoveFirst(); + OLEVariant aValue; + OUString aRet; + while(!aRecordset.IsAtEOF()) + { + WpOLEAppendCollection<ADOFields, ADOField, WpADOField> aFields(aRecordset.GetFields()); + WpADOField aField(aFields.GetItem(0)); + aField.get_Value(aValue); + aRet += aValue.getString() + ","; + aRecordset.MoveNext(); + } + aRecordset.Close(); + if ( !aRet.isEmpty() ) + return aRet.copy(0,aRet.lastIndexOf(',')); + } + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( ) +{ + return getLiteral(DBLITERAL_ESCAPE_PERCENT); +} + +OUString SAL_CALL ODatabaseMetaData::getStringFunctions( ) +{ + OUString aValue; + return aValue.copy(0,aValue.lastIndexOf(',')); +} + +OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( ) +{ + OUString aValue; + return aValue.copy(0,aValue.lastIndexOf(',')); +} + +OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + sal_Int32 nProp = getInt32Property("SQL Support"); + return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ODBC_EXTENDED) == DBPROPVAL_SQL_ODBC_EXTENDED); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar( ) +{ + sal_Int32 nProp = getInt32Property("SQL Support"); + return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ODBC_CORE) == DBPROPVAL_SQL_ODBC_CORE); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + sal_Int32 nProp = getInt32Property("SQL Support"); + return (nProp == 512) || ((nProp & DBPROPVAL_SQL_ODBC_MINIMUM) == DBPROPVAL_SQL_ODBC_MINIMUM); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( ) +{ + if ( ADOS::isJetEngine(m_pConnection->getEngineType()) ) + return true; + return (getInt32Property("Outer Join Capabilities") & 0x00000004L) == 0x00000004L; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return supportsFullOuterJoins( ); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + return getInt32Property("Max Columns in GROUP BY"); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + return getInt32Property("Max Columns in ORDER BY"); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( ) +{ + return getMaxSize(DBLITERAL_USER_NAME); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( sal_Int32 /*setType*/, sal_Int32 /*concurrency*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 setType ) +{ + return ResultSetType::FORWARD_ONLY != setType; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates( ) +{ + return true; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XDatabaseMetaData::getUDTs", *this ); + return Reference< XResultSet >(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ADatabaseMetaDataImpl.cxx b/connectivity/source/drivers/ado/ADatabaseMetaDataImpl.cxx new file mode 100644 index 000000000..34eb7501a --- /dev/null +++ b/connectivity/source/drivers/ado/ADatabaseMetaDataImpl.cxx @@ -0,0 +1,585 @@ +/* -*- 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 <ado/ADatabaseMetaData.hxx> +#include <ado/ADatabaseMetaDataResultSetMetaData.hxx> +#include <ado/Awrapado.hxx> +#include <ado/AGroup.hxx> +#include <ado/adoimp.hxx> +#include <ado/AIndex.hxx> +#include <ado/AKey.hxx> +#include <ado/ATable.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ProcedureResult.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#ifdef DELETE +#undef DELETE +#endif +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/PrivilegeObject.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> + +using namespace connectivity::ado; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::uno; + + +void ODatabaseMetaData::fillLiterals() +{ + ADORecordset *pRecordset = nullptr; + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + m_pADOConnection->OpenSchema(adSchemaDBInfoLiterals,vtEmpty,vtEmpty,&pRecordset); + + ADOS::ThrowException(*m_pADOConnection,*this); + + OSL_ENSURE(pRecordset,"fillLiterals: no resultset!"); + if ( pRecordset ) + { + WpADORecordset aRecordset(pRecordset); + + aRecordset.MoveFirst(); + OLEVariant aValue; + LiteralInfo aInfo; + while(!aRecordset.IsAtEOF()) + { + WpOLEAppendCollection<ADOFields, ADOField, WpADOField> aFields(aRecordset.GetFields()); + WpADOField aField(aFields.GetItem(1)); + aInfo.pwszLiteralValue = aField.get_Value().getString(); + aField = aFields.GetItem(5); + aInfo.fSupported = aField.get_Value().getBool(); + aField = aFields.GetItem(6); + aInfo.cchMaxLen = aField.get_Value().getUInt32(); + + aField = aFields.GetItem(4); + sal_uInt32 nId = aField.get_Value().getUInt32(); + m_aLiteralInfo[nId] = aInfo; + + aRecordset.MoveNext(); + } + aRecordset.Close(); + } +} + +sal_Int32 ODatabaseMetaData::getMaxSize(sal_uInt32 _nId) +{ + if(m_aLiteralInfo.empty()) + fillLiterals(); + + sal_Int32 nSize = 0; + std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId); + if(aIter != m_aLiteralInfo.end() && (*aIter).second.fSupported) + nSize = (static_cast<sal_Int32>((*aIter).second.cchMaxLen) == -1) ? 0 : (*aIter).second.cchMaxLen; + return nSize; +} + +bool ODatabaseMetaData::isCapable(sal_uInt32 _nId) +{ + if(m_aLiteralInfo.empty()) + fillLiterals(); + bool bSupported = false; + std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId); + if(aIter != m_aLiteralInfo.end()) + bSupported = (*aIter).second.fSupported; + return bSupported; +} + + +OUString ODatabaseMetaData::getLiteral(sal_uInt32 _nId) +{ + if(m_aLiteralInfo.empty()) + fillLiterals(); + OUString sStr; + std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId); + if(aIter != m_aLiteralInfo.end() && (*aIter).second.fSupported) + sStr = (*aIter).second.pwszLiteralValue; + return sStr; +} + + +void ODatabaseMetaDataResultSetMetaData::setColumnPrivilegesMap() +{ + m_mColumns[8] = OColumn(OUString(),"IS_GRANTABLE", + ColumnValue::NULLABLE, + 3,3,0, + DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setColumnsMap() +{ + m_mColumns[6] = OColumn(OUString(),"TYPE_NAME", + ColumnValue::NO_NULLS, + 0,0,0, + DataType::VARCHAR); + 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); +} + +void ODatabaseMetaDataResultSetMetaData::setTablesMap() +{ + m_mColumns[5] = OColumn(OUString(),"REMARKS", + ColumnValue::NULLABLE, + 0,0,0, + DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setProcedureColumnsMap() +{ + m_mColumns[12] = OColumn(OUString(),"NULLABLE", + ColumnValue::NO_NULLS, + 1,1,0, + DataType::INTEGER); +} + +void ODatabaseMetaDataResultSetMetaData::setPrimaryKeysMap() +{ + 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() +{ + 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[10] = OColumn(OUString(),"ASC_OR_DESC", + ColumnValue::NULLABLE, + 0,0,0, + DataType::VARCHAR); +} + +void ODatabaseMetaDataResultSetMetaData::setTablePrivilegesMap() +{ + 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[9] = OColumn(OUString(),"KEY_SEQ", + ColumnValue::NO_NULLS, + 1,1,0, + DataType::INTEGER); +} + +void ODatabaseMetaDataResultSetMetaData::setTypeInfoMap() +{ + m_mColumns[3] = OColumn(OUString(),"PRECISION", + ColumnValue::NO_NULLS, + 1,1,0, + DataType::INTEGER); + m_mColumns[7] = OColumn(OUString(),"NULLABLE", + ColumnValue::NO_NULLS, + 1,1,0, + DataType::INTEGER); + m_mColumns[12] = OColumn(OUString(),"AUTO_INCREMENT", + ColumnValue::NO_NULLS, + 1,1,0, + DataType::BIT); + 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() +{ + m_mColumns[7] = OColumn(OUString(),"REMARKS", + ColumnValue::NULLABLE, + 0,0,0, + DataType::VARCHAR); +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSearchable( sal_Int32 column ) +{ + if(!m_mColumns.empty() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isSearchable(); + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + if(!m_mColumns.empty() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isAutoIncrement(); + return false; +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getTableName( sal_Int32 column ) +{ + if(!m_mColumns.empty() && (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(); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCaseSensitive( sal_Int32 column ) +{ + if(!m_mColumns.empty() && (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(); +} + + +ObjectTypeEnum OAdoGroup::MapObjectType(sal_Int32 ObjType) +{ + ObjectTypeEnum eNumType= adPermObjTable; + switch(ObjType) + { + case PrivilegeObject::TABLE: + break; + case PrivilegeObject::VIEW: + eNumType = adPermObjView; + break; + case PrivilegeObject::COLUMN: + eNumType = adPermObjColumn; + break; + } + return eNumType; +} + +sal_Int32 OAdoGroup::MapRight(RightsEnum _eNum) +{ + sal_Int32 nRight = 0; + if(_eNum & adRightRead) + nRight |= Privilege::SELECT; + if(_eNum & adRightInsert) + nRight |= Privilege::INSERT; + if(_eNum & adRightUpdate) + nRight |= Privilege::UPDATE; + if(_eNum & adRightDelete) + nRight |= Privilege::DELETE; + if(_eNum & adRightReadDesign) + nRight |= Privilege::READ; + if(_eNum & adRightCreate) + nRight |= Privilege::CREATE; + if(_eNum & adRightWriteDesign) + nRight |= Privilege::ALTER; + if(_eNum & adRightReference) + nRight |= Privilege::REFERENCE; + if(_eNum & adRightDrop) + nRight |= Privilege::DROP; + + return nRight; +} + +RightsEnum OAdoGroup::Map2Right(sal_Int32 _eNum) +{ + sal_Int32 nRight = adRightNone; + if(_eNum & Privilege::SELECT) + nRight |= adRightRead; + + if(_eNum & Privilege::INSERT) + nRight |= adRightInsert; + + if(_eNum & Privilege::UPDATE) + nRight |= adRightUpdate; + + if(_eNum & Privilege::DELETE) + nRight |= adRightDelete; + + if(_eNum & Privilege::READ) + nRight |= adRightReadDesign; + + if(_eNum & Privilege::CREATE) + nRight |= adRightCreate; + + if(_eNum & Privilege::ALTER) + nRight |= adRightWriteDesign; + + if(_eNum & Privilege::REFERENCE) + nRight |= adRightReference; + + if(_eNum & Privilege::DROP) + nRight |= adRightDrop; + + return static_cast<RightsEnum>(nRight); +} + +void WpADOIndex::Create() +{ + _ADOIndex* pIndex = nullptr; + HRESULT hr = CoCreateInstance(ADOS::CLSID_ADOINDEX_25, + nullptr, + CLSCTX_INPROC_SERVER, + ADOS::IID_ADOINDEX_25, + reinterpret_cast<void**>(&pIndex) ); + + + if( !FAILED( hr ) ) + { + operator=( pIndex ); + pIndex->Release(); + } +} + +void OAdoIndex::fillPropertyValues() +{ + if(m_aIndex.IsValid()) + { + m_Name = m_aIndex.get_Name(); + m_IsUnique = m_aIndex.get_Unique(); + m_IsPrimaryKeyIndex = m_aIndex.get_PrimaryKey(); + m_IsClustered = m_aIndex.get_Clustered(); + } +} + +void WpADOKey::Create() +{ + _ADOKey* pKey = nullptr; + HRESULT hr = CoCreateInstance(ADOS::CLSID_ADOKEY_25, + nullptr, + CLSCTX_INPROC_SERVER, + ADOS::IID_ADOKEY_25, + reinterpret_cast<void**>(&pKey) ); + + + if( !FAILED( hr ) ) + { + operator=( pKey ); + pKey->Release(); + } +} + +void OAdoKey::fillPropertyValues() +{ + if(m_aKey.IsValid()) + { + m_aProps->m_Type = MapKeyRule(m_aKey.get_Type()); + m_Name = m_aKey.get_Name(); + m_aProps->m_ReferencedTable = m_aKey.get_RelatedTable(); + m_aProps->m_UpdateRule = MapRule(m_aKey.get_UpdateRule()); + m_aProps->m_DeleteRule = MapRule(m_aKey.get_DeleteRule()); + } +} + +sal_Int32 OAdoKey::MapRule(const RuleEnum& _eNum) +{ + sal_Int32 eNum = KeyRule::NO_ACTION; + switch(_eNum) + { + case adRICascade: + eNum = KeyRule::CASCADE; + break; + case adRISetNull: + eNum = KeyRule::SET_NULL; + break; + case adRINone: + eNum = KeyRule::NO_ACTION; + break; + case adRISetDefault: + eNum = KeyRule::SET_DEFAULT; + break; + } + return eNum; +} + +RuleEnum OAdoKey::Map2Rule(sal_Int32 _eNum) +{ + RuleEnum eNum = adRINone; + switch(_eNum) + { + case KeyRule::CASCADE: + eNum = adRICascade; + break; + case KeyRule::SET_NULL: + eNum = adRISetNull; + break; + case KeyRule::NO_ACTION: + eNum = adRINone; + break; + case KeyRule::SET_DEFAULT: + eNum = adRISetDefault; + break; + } + return eNum; +} + +sal_Int32 OAdoKey::MapKeyRule(const KeyTypeEnum& _eNum) +{ + sal_Int32 nKeyType = KeyType::PRIMARY; + switch(_eNum) + { + case adKeyPrimary: + nKeyType = KeyType::PRIMARY; + break; + case adKeyForeign: + nKeyType = KeyType::FOREIGN; + break; + case adKeyUnique: + nKeyType = KeyType::UNIQUE; + break; + } + return nKeyType; +} + +KeyTypeEnum OAdoKey::Map2KeyRule(sal_Int32 _eNum) +{ + KeyTypeEnum eNum( adKeyPrimary ); + switch(_eNum) + { + case KeyType::PRIMARY: + eNum = adKeyPrimary; + break; + case KeyType::FOREIGN: + eNum = adKeyForeign; + break; + case KeyType::UNIQUE: + eNum = adKeyUnique; + break; + default: + OSL_FAIL( "OAdoKey::Map2KeyRule: invalid key type!" ); + } + return eNum; +} + +void WpADOTable::Create() +{ + _ADOTable* pTable = nullptr; + HRESULT hr = CoCreateInstance(ADOS::CLSID_ADOTABLE_25, + nullptr, + CLSCTX_INPROC_SERVER, + ADOS::IID_ADOTABLE_25, + reinterpret_cast<void**>(&pTable) ); + + + if( !FAILED( hr ) ) + { + operator=( pTable ); + pTable->Release(); + } +} + +OUString WpADOCatalog::GetObjectOwner(const OUString& _rName, ObjectTypeEnum _eNum) +{ + OLEVariant _rVar; + _rVar.setNoArg(); + OLEString aBSTR; + OLEString sStr1(_rName); + pInterface->GetObjectOwner(sStr1.asBSTR(),_eNum,_rVar,aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void OAdoTable::fillPropertyValues() +{ + if(m_aTable.IsValid()) + { + m_Name = m_aTable.get_Name(); + m_Type = m_aTable.get_Type(); + { + WpADOCatalog aCat(m_aTable.get_ParentCatalog()); + if(aCat.IsValid()) + m_CatalogName = aCat.GetObjectOwner(m_aTable.get_Name(),adPermObjTable); + } + { + WpADOProperties aProps = m_aTable.get_Properties(); + if(aProps.IsValid()) + m_Description = OTools::getValue(aProps,OUString("Description")).getString(); + } + } +} + +void WpADOUser::Create() +{ + _ADOUser* pUser = nullptr; + HRESULT hr = CoCreateInstance(ADOS::CLSID_ADOUSER_25, + nullptr, + CLSCTX_INPROC_SERVER, + ADOS::IID_ADOUSER_25, + reinterpret_cast<void**>(&pUser) ); + + + if( !FAILED( hr ) ) + { + operator=( pUser ); + pUser->Release(); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ADatabaseMetaDataResultSet.cxx b/connectivity/source/drivers/ado/ADatabaseMetaDataResultSet.cxx new file mode 100644 index 000000000..16acbc133 --- /dev/null +++ b/connectivity/source/drivers/ado/ADatabaseMetaDataResultSet.cxx @@ -0,0 +1,1204 @@ +/* -*- 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 <comphelper/sequence.hxx> +#include <ado/ADatabaseMetaDataResultSet.hxx> +#include <ado/ADatabaseMetaDataResultSetMetaData.hxx> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbc/ProcedureResult.hpp> +#include <com/sun/star/sdbc/IndexType.hpp> +#include <comphelper/property.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/seqstream.hxx> +#include <connectivity/dbexception.hxx> + + +#include <oledb.h> + +using namespace dbtools; +using namespace connectivity::ado; +using namespace cppu; +using namespace ::comphelper; + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + + +ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet(ADORecordset* _pRecordSet) + :ODatabaseMetaDataResultSet_BASE(m_aMutex) + ,OPropertySetHelper(ODatabaseMetaDataResultSet_BASE::rBHelper) + ,m_pRecordSet(_pRecordSet) + ,m_aStatement(nullptr) + ,m_nRowPos(0) + ,m_bWasNull(false) + ,m_bEOF(false) + ,m_bOnFirstAfterOpen(false) +{ + osl_atomic_increment( &m_refCount ); + m_aColMapping.push_back(-1); + if(_pRecordSet) + { + m_pRecordSet->AddRef(); + VARIANT_BOOL bIsAtBOF; + m_pRecordSet->get_BOF(&bIsAtBOF); + m_bOnFirstAfterOpen = bIsAtBOF != VARIANT_TRUE; + } + else + m_bOnFirstAfterOpen = false; + osl_atomic_decrement( &m_refCount ); + // allocBuffer(); +} + + +ODatabaseMetaDataResultSet::~ODatabaseMetaDataResultSet() +{ + if(m_pRecordSet) + m_pRecordSet->Release(); +} + +void ODatabaseMetaDataResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + if(m_pRecordSet) + m_pRecordSet->Close(); + m_aStatement = nullptr; + m_xMetaData.clear(); +} + +Any SAL_CALL ODatabaseMetaDataResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + return aRet.hasValue() ? aRet : ODatabaseMetaDataResultSet_BASE::queryInterface(rType); +} + +css::uno::Sequence< css::uno::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::checkRecordSet() +{ + if(!m_pRecordSet) + throwFunctionSequenceException(*this); +} + + +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 ); + assert(false); + return 0; // Never reached +} +#define BLOCK_SIZE 256 + +Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getBinaryStream( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + columnIndex = mapColumn(columnIndex); + WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex); + if((aField.GetAttributes() & adFldLong) == adFldLong) + { + //Copy the data only up to the Actual Size of Field. + sal_Int32 nSize = aField.GetActualSize(); + Sequence<sal_Int8> aData(nSize); + long index = 0; + while(index < nSize) + { + m_aValue = aField.GetChunk(BLOCK_SIZE); + if(m_aValue.isNull()) + break; + UCHAR chData; + for(long index2 = 0;index2 < BLOCK_SIZE;++index2) + { + HRESULT hr = ::SafeArrayGetElement(m_aValue.parray,&index2,&chData); + if(SUCCEEDED(hr)) + { + //Take BYTE by BYTE and advance Memory Location + aData.getArray()[index++] = chData; + } + else + break; + } + } + return index ? Reference< css::io::XInputStream >(new SequenceInputStream(aData)) : Reference< css::io::XInputStream >(); + } + // else we ask for a bytesequence + aField.get_Value(m_aValue); + if(m_aValue.isNull()) + return nullptr; + return new SequenceInputStream(m_aValue.getByteSequence()); +} + +Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getCharacterStream", *this ); + return nullptr; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::getBoolean( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_aValueRange.empty() && columnIndex == 11 && (m_aValueRangeIter = m_aValueRange.find(columnIndex)) != m_aValueRange.end() ) + { + getValue(2); + if ( m_aValue.getInt16() != adCurrency ) + return false; + } + return getValue(columnIndex).getBool(); +} + + +sal_Int8 SAL_CALL ODatabaseMetaDataResultSet::getByte( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + getValue(columnIndex); + + columnIndex = mapColumn(columnIndex); + + if(m_aValue.isNull()) + return 0; + if ( !m_aValueRange.empty() && (m_aValueRangeIter = m_aValueRange.find(columnIndex)) != m_aValueRange.end()) + return static_cast<sal_Int8>((*m_aValueRangeIter).second[m_aValue.getInt32()]); + else if(m_aStrValueRange.size() && (m_aStrValueRangeIter = m_aStrValueRange.find(columnIndex)) != m_aStrValueRange.end()) + return static_cast<sal_Int8>((*m_aStrValueRangeIter).second[m_aValue.getString()]); + + return m_aValue.getInt8(); +} + + +Sequence< sal_Int8 > SAL_CALL ODatabaseMetaDataResultSet::getBytes( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getByteSequence(); +} + + +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 ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + + getValue(columnIndex); + + columnIndex = mapColumn(columnIndex); + if(m_aValue.isNull()) + return 0; + + if(m_aValueRange.size() && (m_aValueRangeIter = m_aValueRange.find(columnIndex)) != m_aValueRange.end()) + return (*m_aValueRangeIter).second[m_aValue.getInt32()]; + else if(m_aStrValueRange.size() && (m_aStrValueRangeIter = m_aStrValueRange.find(columnIndex)) != m_aStrValueRange.end()) + return (*m_aStrValueRangeIter).second[m_aValue.getString()]; + + return m_aValue.getInt32(); +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getRow( ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XResultSet::getRow", *this ); + return 0; +} + + +sal_Int64 SAL_CALL ODatabaseMetaDataResultSet::getLong( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getLong", *this ); + return sal_Int64(0); +} + + +Reference< XResultSetMetaData > SAL_CALL ODatabaseMetaDataResultSet::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + if(!m_xMetaData.is()) + m_xMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + + return m_xMetaData; +} + +Reference< XArray > SAL_CALL ODatabaseMetaDataResultSet::getArray( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRow", *this ); + return nullptr; +} + + +Reference< XClob > SAL_CALL ODatabaseMetaDataResultSet::getClob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRow", *this ); + return nullptr; +} + +Reference< XBlob > SAL_CALL ODatabaseMetaDataResultSet::getBlob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRow", *this ); + return nullptr; +} + + +Reference< XRef > SAL_CALL ODatabaseMetaDataResultSet::getRef( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRow", *this ); + return nullptr; +} + + +Any SAL_CALL ODatabaseMetaDataResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + columnIndex = mapColumn(columnIndex); + return Any(); +} + + +sal_Int16 SAL_CALL ODatabaseMetaDataResultSet::getShort( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + getValue(columnIndex); + + columnIndex = mapColumn(columnIndex); + if(m_aValue.isNull()) + return 0; + + if(m_aValueRange.size() && (m_aValueRangeIter = m_aValueRange.find(columnIndex)) != m_aValueRange.end()) + return static_cast<sal_Int16>((*m_aValueRangeIter).second[m_aValue.getInt32()]); + else if(m_aStrValueRange.size() && (m_aStrValueRangeIter = m_aStrValueRange.find(columnIndex)) != m_aStrValueRange.end()) + return static_cast<sal_Int16>((*m_aStrValueRangeIter).second[m_aValue.getString()]); + + return m_aValue.getInt16(); +} + + +OUString SAL_CALL ODatabaseMetaDataResultSet::getString( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + getValue(columnIndex); + + + columnIndex = mapColumn(columnIndex); + if(m_aValue.isNull()) + return OUString(); + if(m_aIntValueRange.size() && (m_aIntValueRangeIter = m_aIntValueRange.find(columnIndex)) != m_aIntValueRange.end()) + return (*m_aIntValueRangeIter).second[m_aValue.getInt32()]; + + return m_aValue.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( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + VARIANT_BOOL bIsAtEOF; + m_pRecordSet->get_EOF(&bIsAtEOF); + return bIsAtEOF == VARIANT_TRUE; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + return m_nRowPos == 1; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + return true; +} + +void SAL_CALL ODatabaseMetaDataResultSet::beforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + if(first()) + previous(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::afterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + if(last()) + next(); + m_bEOF = true; +} + + +void SAL_CALL ODatabaseMetaDataResultSet::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + } + dispose(); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::first( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + + if(!m_pRecordSet) + return false; + + bool bRet = SUCCEEDED(m_pRecordSet->MoveFirst()); + if ( bRet ) + m_nRowPos = 1; + return bRet; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + + + return m_pRecordSet && SUCCEEDED(m_pRecordSet->MoveLast()); +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 row ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + + if(first()) + { + OLEVariant aEmpty; + aEmpty.setNoArg(); + bool bRet = SUCCEEDED(m_pRecordSet->Move(row,aEmpty)); + if(bRet) + m_nRowPos = row; + return bRet; + } + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 row ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + + if(!m_pRecordSet) + return false; + + OLEVariant aEmpty; + aEmpty.setNoArg(); + bool bRet = SUCCEEDED(m_pRecordSet->Move(row,aEmpty)); + if(bRet) + m_nRowPos += row; + return bRet; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + + if(!m_pRecordSet) + return false; + + bool bRet = SUCCEEDED(m_pRecordSet->MovePrevious()); + if(bRet) + --m_nRowPos; + return bRet; +} + +Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( ) +{ + return m_aStatement.get(); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + sal_Int32 eRec; + m_pRecordSet->get_Status(&eRec); + return (RecordStatusEnum(eRec) & adRecDeleted) == adRecDeleted; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( ) +{ ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + sal_Int32 eRec; + m_pRecordSet->get_Status(&eRec); + return (RecordStatusEnum(eRec) & adRecNew) == adRecNew; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + sal_Int32 eRec; + m_pRecordSet->get_Status(&eRec); + return (RecordStatusEnum(eRec) & adRecModified) == adRecModified; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isBeforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + + if(!m_pRecordSet) + return true; + + VARIANT_BOOL bIsAtBOF; + m_pRecordSet->get_BOF(&bIsAtBOF); + return bIsAtBOF == VARIANT_TRUE; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::next( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + + if(!m_pRecordSet) + return false; + + if(m_bOnFirstAfterOpen) + { + m_bOnFirstAfterOpen = false; + return true; + } + else + return SUCCEEDED(m_pRecordSet->MoveNext()); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::wasNull( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + return m_aValue.isNull(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::refreshRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + m_pRecordSet->Resync(adAffectCurrent); +} + + +void SAL_CALL ODatabaseMetaDataResultSet::cancel( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + + m_pRecordSet->Cancel(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::clearWarnings( ) +{ +} + +Any SAL_CALL ODatabaseMetaDataResultSet::getWarnings( ) +{ + return Any(); +} + +sal_Int32 ODatabaseMetaDataResultSet::getResultSetConcurrency() +{ + return ResultSetConcurrency::READ_ONLY; +} + +sal_Int32 ODatabaseMetaDataResultSet::getResultSetType() +{ + return ResultSetType::FORWARD_ONLY; +} + +sal_Int32 ODatabaseMetaDataResultSet::getFetchDirection() +{ + return FetchDirection::FORWARD; +} + +sal_Int32 ODatabaseMetaDataResultSet::getFetchSize() const +{ + sal_Int32 nValue=-1; + if(m_pRecordSet) + m_pRecordSet->get_CacheSize(&nValue); + return nValue; +} + +OUString ODatabaseMetaDataResultSet::getCursorName() +{ + return OUString(); +} + + +void ODatabaseMetaDataResultSet::setFetchDirection(sal_Int32 /*_par0*/) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "ResultSet::FetchDirection", *this ); +} + +void ODatabaseMetaDataResultSet::setFetchSize(sal_Int32 _par0) +{ + if(m_pRecordSet) + m_pRecordSet->put_CacheSize(_par0); +} + +::cppu::IPropertyArrayHelper* ODatabaseMetaDataResultSet::createArrayHelper( ) const +{ + + Sequence< css::beans::Property > aProps(5); + css::beans::Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper & ODatabaseMetaDataResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool ODatabaseMetaDataResultSet::convertFastPropertyValue( + Any & rConvertedValue, + Any & rOldValue, + sal_Int32 nHandle, + const Any& rValue ) +{ + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection()); + case PROPERTY_ID_FETCHSIZE: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize()); + default: + ; + } + return false; +} + +void ODatabaseMetaDataResultSet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const Any& /*rValue*/ + ) +{ + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + throw Exception("cannot set prop " + OUString::number(nHandle), nullptr); + default: + OSL_FAIL("setFastPropertyValue_NoBroadcast: Illegal handle value!"); + } +} + +void ODatabaseMetaDataResultSet::getFastPropertyValue( + Any& rValue, + sal_Int32 nHandle + ) const +{ + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + rValue <<= getCursorName(); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= getResultSetConcurrency(); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= getResultSetType(); + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= getFetchDirection(); + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= getFetchSize(); + break; + } +} + +void ODatabaseMetaDataResultSet::setProceduresMap() +{ + + for(sal_Int32 i=1;i<4;i++) + m_aColMapping.push_back(i); + m_aColMapping.push_back(5); + m_aColMapping.push_back(7); + m_aColMapping.push_back(8); + m_aColMapping.push_back(6); + m_aColMapping.push_back(4); + + ::std::map<sal_Int32,sal_Int32> aMap; + aMap[DB_PT_UNKNOWN] = ProcedureResult::UNKNOWN; + aMap[DB_PT_PROCEDURE] = ProcedureResult::NONE; + aMap[DB_PT_FUNCTION] = ProcedureResult::RETURN; + m_aValueRange[4] = aMap; + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setProceduresMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setCatalogsMap() +{ + m_aColMapping.push_back(1); + + m_xMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); +} + +void ODatabaseMetaDataResultSet::setSchemasMap() +{ + m_aColMapping.push_back(2); + + m_xMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); +} + +void ODatabaseMetaDataResultSet::setColumnPrivilegesMap() +{ + + m_aColMapping.push_back(3); + m_aColMapping.push_back(4); + m_aColMapping.push_back(5); + m_aColMapping.push_back(6); + m_aColMapping.push_back(2); + m_aColMapping.push_back(9); + m_aColMapping.push_back(10); + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setColumnPrivilegesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setColumnsMap() +{ + + for(sal_Int32 i=1;i<5;++i) + m_aColMapping.push_back(i); + + m_aColMapping.push_back(12); + m_aColMapping.push_back(12); // is used as TYPE_NAME + + m_aColMapping.push_back(14); + m_aColMapping.push_back(6); + m_aColMapping.push_back(17); + m_aColMapping.push_back(18); + + m_aColMapping.push_back(11); + m_aColMapping.push_back(29); + m_aColMapping.push_back(9); + m_aColMapping.push_back(18); + m_aColMapping.push_back(18); + + m_aColMapping.push_back(15); + m_aColMapping.push_back(7); + m_aColMapping.push_back(11); + + ::std::map<sal_Int32,sal_Int32> aMap; + aMap[adEmpty] = ADOS::MapADOType2Jdbc(adEmpty); + aMap[adTinyInt] = ADOS::MapADOType2Jdbc(adTinyInt); + aMap[adSmallInt] = ADOS::MapADOType2Jdbc(adSmallInt); + aMap[adInteger] = ADOS::MapADOType2Jdbc(adInteger); + aMap[adBigInt] = ADOS::MapADOType2Jdbc(adBigInt); + aMap[adUnsignedTinyInt] = ADOS::MapADOType2Jdbc(adUnsignedTinyInt); + aMap[adUnsignedSmallInt]= ADOS::MapADOType2Jdbc(adUnsignedSmallInt); + aMap[adUnsignedInt] = ADOS::MapADOType2Jdbc(adUnsignedInt); + aMap[adUnsignedBigInt] = ADOS::MapADOType2Jdbc(adUnsignedBigInt); + aMap[adSingle] = ADOS::MapADOType2Jdbc(adSingle); + aMap[adDouble] = ADOS::MapADOType2Jdbc(adDouble); + aMap[adCurrency] = ADOS::MapADOType2Jdbc(adCurrency); + aMap[adDecimal] = ADOS::MapADOType2Jdbc(adDecimal); + aMap[adNumeric] = ADOS::MapADOType2Jdbc(adNumeric); + aMap[adBoolean] = ADOS::MapADOType2Jdbc(adBoolean); + aMap[adError] = ADOS::MapADOType2Jdbc(adError); + aMap[adUserDefined] = ADOS::MapADOType2Jdbc(adUserDefined); + aMap[adVariant] = ADOS::MapADOType2Jdbc(adVariant); + aMap[adIDispatch] = ADOS::MapADOType2Jdbc(adIDispatch); + aMap[adIUnknown] = ADOS::MapADOType2Jdbc(adIUnknown); + aMap[adGUID] = ADOS::MapADOType2Jdbc(adGUID); + aMap[adDate] = ADOS::MapADOType2Jdbc(adDate); + aMap[adDBDate] = ADOS::MapADOType2Jdbc(adDBDate); + aMap[adDBTime] = ADOS::MapADOType2Jdbc(adDBTime); + aMap[adDBTimeStamp] = ADOS::MapADOType2Jdbc(adDBTimeStamp); + aMap[adBSTR] = ADOS::MapADOType2Jdbc(adBSTR); + aMap[adChar] = ADOS::MapADOType2Jdbc(adChar); + aMap[adVarChar] = ADOS::MapADOType2Jdbc(adVarChar); + aMap[adLongVarChar] = ADOS::MapADOType2Jdbc(adLongVarChar); + aMap[adWChar] = ADOS::MapADOType2Jdbc(adWChar); + aMap[adVarWChar] = ADOS::MapADOType2Jdbc(adVarWChar); + aMap[adLongVarWChar] = ADOS::MapADOType2Jdbc(adLongVarWChar); + aMap[adBinary] = ADOS::MapADOType2Jdbc(adBinary); + aMap[adVarBinary] = ADOS::MapADOType2Jdbc(adVarBinary); + aMap[adLongVarBinary] = ADOS::MapADOType2Jdbc(adLongVarBinary); + aMap[adChapter] = ADOS::MapADOType2Jdbc(adChapter); + aMap[adFileTime] = ADOS::MapADOType2Jdbc(adFileTime); + aMap[adPropVariant] = ADOS::MapADOType2Jdbc(adPropVariant); + aMap[adVarNumeric] = ADOS::MapADOType2Jdbc(adVarNumeric); + + m_aValueRange[12] = aMap; + + std::map< sal_Int32,OUString> aMap2; + aMap2[0] = "YES"; + aMap2[1] = "NO"; + m_aIntValueRange[18] = aMap2; + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTablesMap() +{ + + for(sal_Int32 i=1;i<5;i++) + m_aColMapping.push_back(i); + m_aColMapping.push_back(6); + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setTablesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setProcedureColumnsMap() +{ + + for(sal_Int32 i=1;i<5;i++) + m_aColMapping.push_back(i); + m_aColMapping.push_back(6); + m_aColMapping.push_back(10); + m_aColMapping.push_back(16); + m_aColMapping.push_back(13); + m_aColMapping.push_back(11); + m_aColMapping.push_back(12); + + m_aColMapping.push_back(9); + m_aColMapping.push_back(14); + + ::std::map<sal_Int32,sal_Int32> aMap; + aMap[DBTYPE_EMPTY] = DataType::SQLNULL; + aMap[DBTYPE_NULL] = DataType::SQLNULL; + aMap[DBTYPE_I2] = DataType::SMALLINT; + aMap[DBTYPE_I4] = DataType::INTEGER; + aMap[DBTYPE_R4] = DataType::FLOAT; + aMap[DBTYPE_R8] = DataType::DOUBLE; + aMap[DBTYPE_CY] = DataType::BIGINT; + aMap[DBTYPE_DATE] = DataType::DATE; + aMap[DBTYPE_BSTR] = DataType::VARCHAR; + aMap[DBTYPE_IDISPATCH] = DataType::OBJECT; + aMap[DBTYPE_ERROR] = DataType::OTHER; + aMap[DBTYPE_BOOL] = DataType::BIT; + aMap[DBTYPE_VARIANT] = DataType::STRUCT; + aMap[DBTYPE_IUNKNOWN] = DataType::OTHER; + aMap[DBTYPE_DECIMAL] = DataType::DECIMAL; + aMap[DBTYPE_UI1] = DataType::TINYINT; + aMap[DBTYPE_ARRAY] = DataType::ARRAY; + aMap[DBTYPE_BYREF] = DataType::REF; + aMap[DBTYPE_I1] = DataType::CHAR; + aMap[DBTYPE_UI2] = DataType::SMALLINT; + aMap[DBTYPE_UI4] = DataType::INTEGER; + + // aMap[The] = ; + // aMap[in] = ; + aMap[DBTYPE_I8] = DataType::BIGINT; + aMap[DBTYPE_UI8] = DataType::BIGINT; + aMap[DBTYPE_GUID] = DataType::OTHER; + aMap[DBTYPE_VECTOR] = DataType::OTHER; + aMap[DBTYPE_FILETIME] = DataType::OTHER; + aMap[DBTYPE_RESERVED] = DataType::OTHER; + + // aMap[The] = ; + aMap[DBTYPE_BYTES] = DataType::VARBINARY; + aMap[DBTYPE_STR] = DataType::LONGVARCHAR; + aMap[DBTYPE_WSTR] = DataType::LONGVARCHAR; + aMap[DBTYPE_NUMERIC] = DataType::NUMERIC; + aMap[DBTYPE_UDT] = DataType::OTHER; + aMap[DBTYPE_DBDATE] = DataType::DATE; + aMap[DBTYPE_DBTIME] = DataType::TIME; + aMap[DBTYPE_DBTIMESTAMP] = DataType::TIMESTAMP; + aMap[DBTYPE_HCHAPTER] = DataType::OTHER; + aMap[DBTYPE_PROPVARIANT] = DataType::OTHER; + aMap[DBTYPE_VARNUMERIC] = DataType::NUMERIC; + + m_aValueRange[10] = aMap; + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setProcedureColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setPrimaryKeysMap() +{ + + sal_Int32 i=1; + for(;i<5;i++) + m_aColMapping.push_back(i); + m_aColMapping.push_back(7); + m_aColMapping.push_back(8); + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setProcedureColumnsMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setIndexInfoMap() +{ + + sal_Int32 i=1; + for(;i<4;i++) + m_aColMapping.push_back(i); + m_aColMapping.push_back(8); + m_aColMapping.push_back(4); + m_aColMapping.push_back(6); + m_aColMapping.push_back(10); + m_aColMapping.push_back(17); + m_aColMapping.push_back(18); + m_aColMapping.push_back(21); + m_aColMapping.push_back(22); + m_aColMapping.push_back(23); + m_aColMapping.push_back(24); + + ::std::map<sal_Int32,sal_Int32> aMap; + aMap[DBPROPVAL_IT_HASH] = IndexType::HASHED; + aMap[DBPROPVAL_IT_CONTENT] = IndexType::OTHER; + aMap[DBPROPVAL_IT_OTHER] = IndexType::OTHER; + aMap[DBPROPVAL_IT_BTREE] = IndexType::OTHER; + + m_aValueRange[10] = aMap; + + ::std::map<sal_Int32,sal_Int32> aMap2; + aMap[0] = 1; + aMap[1] = 0; + m_aValueRange[8] = aMap2; + + std::map< sal_Int32,OUString> aMap3; + aMap3[0] = ""; + aMap3[DB_COLLATION_ASC] = "A"; + aMap3[DB_COLLATION_DESC] = "D"; + + m_aIntValueRange[21] = aMap3; + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setIndexInfoMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTablePrivilegesMap() +{ + + sal_Int32 i=3; + for(;i<6;i++) + m_aColMapping.push_back(i); + m_aColMapping.push_back(1); + m_aColMapping.push_back(2); + m_aColMapping.push_back(6); + m_aColMapping.push_back(7); + + std::map< sal_Int32,OUString> aMap; + aMap[0] = "YES"; + aMap[1] = "NO"; + m_aIntValueRange[7] = aMap; + + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setTablePrivilegesMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setCrossReferenceMap() +{ + + sal_Int32 i=1; + for(;i<5;i++) + m_aColMapping.push_back(i); + for(i=7;i<11;i++) + m_aColMapping.push_back(i); + + m_aColMapping.push_back(13); + m_aColMapping.push_back(14); + m_aColMapping.push_back(15); + m_aColMapping.push_back(17); + m_aColMapping.push_back(16); + m_aColMapping.push_back(18); + + std::map< OUString,sal_Int32> aMap; + aMap[ OUString("CASCADE")] = KeyRule::CASCADE; + aMap[ OUString("RESTRICT")] = KeyRule::RESTRICT; + aMap[ OUString("SET NULL")] = KeyRule::SET_NULL; + aMap[ OUString("SET DEFAULT")] = KeyRule::SET_DEFAULT; + aMap[ OUString("NO ACTION")] = KeyRule::NO_ACTION; + + m_aStrValueRange[14] = aMap; + m_aStrValueRange[15] = aMap; + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setCrossReferenceMap(); + m_xMetaData = pMetaData; +} + +void ODatabaseMetaDataResultSet::setTypeInfoMap(bool _bJetEngine) +{ + sal_Int32 i=1; + for(;i<19;i++) + m_aColMapping.push_back(i); + + std::map< OUString,sal_Int32> aMap1; + aMap1[ OUString()] = 10; + + m_aStrValueRange[18] = aMap1; + + ::std::map<sal_Int32,sal_Int32> aMap; + aMap[adEmpty] = ADOS::MapADOType2Jdbc(adEmpty); + aMap[adTinyInt] = ADOS::MapADOType2Jdbc(adTinyInt); + aMap[adSmallInt] = ADOS::MapADOType2Jdbc(adSmallInt); + aMap[adInteger] = ADOS::MapADOType2Jdbc(adInteger); + aMap[adBigInt] = ADOS::MapADOType2Jdbc(adBigInt); + aMap[adUnsignedTinyInt] = ADOS::MapADOType2Jdbc(adUnsignedTinyInt); + aMap[adUnsignedSmallInt]= ADOS::MapADOType2Jdbc(adUnsignedSmallInt); + aMap[adUnsignedInt] = ADOS::MapADOType2Jdbc(adUnsignedInt); + aMap[adUnsignedBigInt] = ADOS::MapADOType2Jdbc(adUnsignedBigInt); + aMap[adSingle] = ADOS::MapADOType2Jdbc(adSingle); + aMap[adDouble] = ADOS::MapADOType2Jdbc(adDouble); + aMap[adCurrency] = ADOS::MapADOType2Jdbc(adCurrency); + aMap[adDecimal] = ADOS::MapADOType2Jdbc(adDecimal); + aMap[adNumeric] = ADOS::MapADOType2Jdbc(adNumeric); + aMap[adBoolean] = ADOS::MapADOType2Jdbc(adBoolean); + aMap[adError] = ADOS::MapADOType2Jdbc(adError); + aMap[adUserDefined] = ADOS::MapADOType2Jdbc(adUserDefined); + aMap[adVariant] = ADOS::MapADOType2Jdbc(adVariant); + aMap[adIDispatch] = ADOS::MapADOType2Jdbc(adIDispatch); + aMap[adIUnknown] = ADOS::MapADOType2Jdbc(adIUnknown); + aMap[adGUID] = ADOS::MapADOType2Jdbc(adGUID); + aMap[adDate] = _bJetEngine ? ADOS::MapADOType2Jdbc(adDBTimeStamp) : ADOS::MapADOType2Jdbc(adDate); + aMap[adDBDate] = ADOS::MapADOType2Jdbc(adDBDate); + aMap[adDBTime] = ADOS::MapADOType2Jdbc(adDBTime); + aMap[adDBTimeStamp] = ADOS::MapADOType2Jdbc(adDBTimeStamp); + aMap[adBSTR] = ADOS::MapADOType2Jdbc(adBSTR); + aMap[adChar] = ADOS::MapADOType2Jdbc(adChar); + aMap[adVarChar] = ADOS::MapADOType2Jdbc(adVarChar); + aMap[adLongVarChar] = ADOS::MapADOType2Jdbc(adLongVarChar); + aMap[adWChar] = ADOS::MapADOType2Jdbc(adWChar); + aMap[adVarWChar] = ADOS::MapADOType2Jdbc(adVarWChar); + aMap[adLongVarWChar] = ADOS::MapADOType2Jdbc(adLongVarWChar); + aMap[adBinary] = ADOS::MapADOType2Jdbc(adBinary); + aMap[adVarBinary] = ADOS::MapADOType2Jdbc(adVarBinary); + aMap[adLongVarBinary] = ADOS::MapADOType2Jdbc(adLongVarBinary); + aMap[adChapter] = ADOS::MapADOType2Jdbc(adChapter); + aMap[adFileTime] = ADOS::MapADOType2Jdbc(adFileTime); + aMap[adPropVariant] = ADOS::MapADOType2Jdbc(adPropVariant); + aMap[adVarNumeric] = ADOS::MapADOType2Jdbc(adVarNumeric); +// aMap[adArray] = ADOS::MapADOType2Jdbc(adArray); + + m_aValueRange[2] = aMap; + + ::std::map<sal_Int32,sal_Int32> aColumnValueMapping; + aColumnValueMapping[VARIANT_FALSE] = ColumnValue::NO_NULLS; + aColumnValueMapping[VARIANT_TRUE] = ColumnValue::NULLABLE; + m_aValueRange[7] = aColumnValueMapping; + + // now adjust the column mapping + // OJ 24.01.2002 96860 + ::std::map<sal_Int32,sal_Int32> aSearchMapping; + aSearchMapping[DB_UNSEARCHABLE] = ColumnSearch::NONE; + aSearchMapping[DB_LIKE_ONLY] = ColumnSearch::CHAR; + aSearchMapping[DB_ALL_EXCEPT_LIKE] = ColumnSearch::BASIC; + aSearchMapping[DB_SEARCHABLE] = ColumnSearch::FULL; + + m_aValueRange[9] = aSearchMapping; + + ::std::map<sal_Int32,sal_Int32> aCurrencyMapping; + m_aValueRange[11] = aCurrencyMapping; + + ODatabaseMetaDataResultSetMetaData* pMetaData = new ODatabaseMetaDataResultSetMetaData(m_pRecordSet,this); + pMetaData->setTypeInfoMap(); + m_xMetaData = pMetaData; +} + +void SAL_CALL ODatabaseMetaDataResultSet::acquire() throw() +{ + ODatabaseMetaDataResultSet_BASE::acquire(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::release() throw() +{ + ODatabaseMetaDataResultSet_BASE::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODatabaseMetaDataResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +OLEVariant ODatabaseMetaDataResultSet::getValue(sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + + checkRecordSet(); + + WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex); + aField.get_Value(m_aValue); + return m_aValue; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData.cxx b/connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData.cxx new file mode 100644 index 000000000..9a4365abf --- /dev/null +++ b/connectivity/source/drivers/ado/ADatabaseMetaDataResultSetMetaData.cxx @@ -0,0 +1,222 @@ +/* -*- 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 <ado/ADatabaseMetaDataResultSetMetaData.hxx> +#include <ado/Awrapado.hxx> +#include <connectivity/dbexception.hxx> + + +using namespace connectivity; +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + + +ODatabaseMetaDataResultSetMetaData::~ODatabaseMetaDataResultSetMetaData() +{ + if(m_pRecordSet) + m_pRecordSet->Release(); +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + sal_Int32 nSize = 0; + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + nSize = (*m_mColumnsIter).second.getColumnDisplaySize(); + else if(m_pRecordSet) + { + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + nSize = aField.GetActualSize(); + } + return nSize; +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnType( sal_Int32 column ) +{ + sal_Int32 nType = 0; + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + nType = (*m_mColumnsIter).second.getColumnType(); + else if(m_pRecordSet) + { + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + nType = ADOS::MapADOType2Jdbc(aField.GetADOType()); + } + return nType; +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnCount( ) +{ + if(!m_pRecordSet) + return 0; + if(m_nColCount != -1) + return m_nColCount; + + if(m_vMapping.size()) + return m_mColumns.size(); + + ADOFields* pFields = nullptr; + m_pRecordSet->get_Fields(&pFields); + WpOLEAppendCollection<ADOFields, ADOField, WpADOField> aFields(pFields); + m_nColCount = aFields.GetItemCount(); + return m_nColCount; +} + + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnName( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getColumnName(); + if(!m_pRecordSet) + return OUString(); + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + return aField.GetName(); + + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getColumnLabel(); + return getColumnName(column); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCurrency( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isCurrency(); + if(!m_pRecordSet) + return false; + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + { + return (aField.GetAttributes() & adFldFixed) == adFldFixed; + } + return false; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSigned( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isSigned(); + if(!m_pRecordSet) + return false; + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + { + return (aField.GetAttributes() & adFldNegativeScale) == adFldNegativeScale; + } + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getPrecision( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getPrecision(); + if(!m_pRecordSet) + return 0; + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + return aField.GetPrecision(); + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::getScale( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.getScale(); + + if(!m_pRecordSet) + return 0; + + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + return aField.GetNumericScale(); + return 0; +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSetMetaData::isNullable( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isNullable(); + + if(!m_pRecordSet) + return sal_Int32(false); + + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + { + return sal_Int32((aField.GetAttributes() & adFldIsNullable) == adFldIsNullable); + } + return sal_Int32(false); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isReadOnly( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isReadOnly(); + + if(!m_pRecordSet) + return false; + + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + { + // return (aField.GetStatus() & adFieldReadOnly) == adFieldReadOnly; + } + return false; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isDefinitelyWritable(); + + if(!m_pRecordSet) + return false; + + WpADOField aField = ADOS::getField(m_pRecordSet,m_vMapping[column]); + if(aField.IsValid()) + { + return (aField.GetAttributes() & adFldUpdatable) == adFldUpdatable; + } + return false; +; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isWritable( sal_Int32 column ) +{ + if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end()) + return (*m_mColumnsIter).second.isWritable(); + return isDefinitelyWritable(column); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ADriver.cxx b/connectivity/source/drivers/ado/ADriver.cxx new file mode 100644 index 000000000..926a818ee --- /dev/null +++ b/connectivity/source/drivers/ado/ADriver.cxx @@ -0,0 +1,278 @@ +/* -*- 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 <ado/ADriver.hxx> +#include <ado/AConnection.hxx> +#include <ado/Awrapadox.hxx> +#include <ado/ACatalog.hxx> +#include <ado/Awrapado.hxx> +#include <ado/adoimp.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <strings.hrc> +#include <objbase.h> + +#include <resource/sharedresources.hxx> + +#include <memory> + +using namespace connectivity; +using namespace connectivity::ado; +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::sdbcx; + + +ODriver::ODriver(const css::uno::Reference< css::lang::XMultiServiceFactory >& _xORB) + : ODriver_BASE(m_aMutex) + ,m_xORB(_xORB) +{ + if ( FAILED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)) ) + { + CoUninitialize(); + int h = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + (void)h; + ++h; + } +} + +ODriver::~ODriver() +{ + CoUninitialize(); + CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); +} + +void ODriver::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + + for (auto& rxConnection : m_xConnections) + { + Reference< XComponent > xComp(rxConnection.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + } + m_xConnections.clear(); + + ODriver_BASE::disposing(); +} +// static ServiceInfo + +OUString ODriver::getImplementationName_Static( ) +{ + return "com.sun.star.comp.sdbc.ado.ODriver"; +} + +Sequence< OUString > ODriver::getSupportedServiceNames_Static( ) +{ + return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" }; +} + +css::uno::Reference< css::uno::XInterface > connectivity::ado::ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory) +{ + return *(new ODriver(_rxFactory)); +} + + +OUString SAL_CALL ODriver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL ODriver::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +Sequence< OUString > SAL_CALL ODriver::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + + +Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url, const Sequence< PropertyValue >& info ) +{ + if ( ! acceptsURL(url) ) + return nullptr; + + // we need to wrap the connection as the construct call might throw + std::unique_ptr<OConnection> pCon(new OConnection(this)); + pCon->construct(url,info); + OConnection* pPtr = pCon.get(); + Reference< XConnection > xCon = pCon.release(); + m_xConnections.push_back(WeakReferenceHelper(*pPtr)); + + return xCon; +} + +sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url ) +{ + return url.startsWith("sdbc:ado:"); +} + +void ODriver::impl_checkURL_throw(const OUString& _sUrl) +{ + if ( !acceptsURL(_sUrl) ) + { + SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } // if ( !acceptsURL(_sUrl) ) +} + +Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) +{ + impl_checkURL_throw(url); + if ( acceptsURL(url) ) + { + std::vector< DriverPropertyInfo > aDriverInfo; + + Sequence< OUString > aBooleanValues(2); + aBooleanValues[0] = "false"; + aBooleanValues[1] = "true"; + + aDriverInfo.push_back(DriverPropertyInfo( + "IgnoreDriverPrivileges" + ,"Ignore the privileges from the database driver." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "EscapeDateTime" + ,"Escape date time format." + ,false + ,"true" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "TypeInfoSettings" + ,"Defines how the type info of the database metadata should be manipulated." + ,false + ,OUString( ) + ,Sequence< OUString > ()) + ); + return Sequence< DriverPropertyInfo >(aDriverInfo.data(),aDriverInfo.size()); + } + return Sequence< DriverPropertyInfo >(); +} + +sal_Int32 SAL_CALL ODriver::getMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL ODriver::getMinorVersion( ) +{ + return 0; +} + +// XDataDefinitionSupplier +Reference< XTablesSupplier > SAL_CALL ODriver::getDataDefinitionByConnection( const Reference< css::sdbc::XConnection >& connection ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (ODriver_BASE::rBHelper.bDisposed) + throw DisposedException(); + + OConnection* pConnection = nullptr; + Reference< css::lang::XUnoTunnel> xTunnel(connection,UNO_QUERY); + if(xTunnel.is()) + { + OConnection* pSearchConnection = reinterpret_cast< OConnection* >( xTunnel->getSomething(OConnection::getUnoTunnelId()) ); + + auto foundConnection = std::any_of(m_xConnections.begin(), m_xConnections.end(), + [&pSearchConnection](const css::uno::WeakReferenceHelper& rxConnection) { + return static_cast<OConnection*>(Reference< XConnection >::query(rxConnection.get().get()).get()) == pSearchConnection; }); + if (foundConnection) + pConnection = pSearchConnection; + } + + Reference< XTablesSupplier > xTab; + if(pConnection) + { + WpADOCatalog aCatalog; + aCatalog.Create(); + if(aCatalog.IsValid()) + { + aCatalog.putref_ActiveConnection(*pConnection->getConnection()); + OCatalog* pCatalog = new OCatalog(aCatalog,pConnection); + xTab = pCatalog; + pConnection->setCatalog(xTab); + pConnection->setCatalog(pCatalog); + } + } + return xTab; +} + +Reference< XTablesSupplier > SAL_CALL ODriver::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info ) +{ + impl_checkURL_throw(url); + return getDataDefinitionByConnection(connect(url,info)); +} + + +void ADOS::ThrowException(ADOConnection* _pAdoCon,const Reference< XInterface >& _xInterface) +{ + ADOErrors *pErrors = nullptr; + _pAdoCon->get_Errors(&pErrors); + if(!pErrors) + return; // no error found + + pErrors->AddRef( ); + + // read all noted errors and issue them + sal_Int32 nLen; + pErrors->get_Count(&nLen); + if (nLen) + { + SQLException aException; + aException.ErrorCode = 1000; + for (sal_Int32 i = nLen-1; i>=0; --i) + { + ADOError *pError = nullptr; + pErrors->get_Item(OLEVariant(i),&pError); + WpADOError aErr(pError); + OSL_ENSURE(pError,"No error in collection found! BAD!"); + if(pError) + { + if(i==nLen-1) + aException = SQLException(aErr.GetDescription(),_xInterface,aErr.GetSQLState(),aErr.GetNumber(),Any()); + else + { + SQLException aTemp(aErr.GetDescription(), + _xInterface,aErr.GetSQLState(),aErr.GetNumber(),makeAny(aException)); + aTemp.NextException <<= aException; + aException = aTemp; + } + } + } + pErrors->Clear(); + pErrors->Release(); + throw aException; + } + pErrors->Release(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AGroup.cxx b/connectivity/source/drivers/ado/AGroup.cxx new file mode 100644 index 000000000..b41fbdbba --- /dev/null +++ b/connectivity/source/drivers/ado/AGroup.cxx @@ -0,0 +1,157 @@ +/* -*- 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 <ado/AGroup.hxx> +#include <ado/AUsers.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <ado/AConnection.hxx> +#include <TConnection.hxx> + +using namespace connectivity::ado; +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::sdbcx; + + +void WpADOGroup::Create() +{ + ADOGroup* pGroup = nullptr; + HRESULT hr = CoCreateInstance(ADOS::CLSID_ADOGROUP_25, + nullptr, + CLSCTX_INPROC_SERVER, + ADOS::IID_ADOGROUP_25, + reinterpret_cast<void**>(&pGroup) ); + + + if( !FAILED( hr ) ) + { + operator=( pGroup ); + pGroup->Release(); + } +} + +OAdoGroup::OAdoGroup(OCatalog* _pParent,bool _bCase, ADOGroup* _pGroup) : OGroup_ADO(_bCase),m_pCatalog(_pParent) +{ + construct(); + if(_pGroup) + m_aGroup = WpADOGroup(_pGroup); + else + m_aGroup.Create(); + +} + +OAdoGroup::OAdoGroup(OCatalog* _pParent,bool _bCase, const OUString& Name) : OGroup_ADO(Name,_bCase),m_pCatalog(_pParent) +{ + construct(); + m_aGroup.Create(); + m_aGroup.put_Name(Name); +} + +void OAdoGroup::refreshUsers() +{ + ::std::vector< OUString> aVector; + + WpADOUsers aUsers = m_aGroup.get_Users(); + aUsers.fillElementNames(aVector); + + if(m_pUsers) + m_pUsers->reFill(aVector); + else + m_pUsers.reset(new OUsers(m_pCatalog, m_aMutex, aVector, aUsers, isCaseSensitive())); +} + +Sequence< sal_Int8 > OAdoGroup::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OAdoGroup::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OAdoGroup>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : OGroup_ADO::getSomething(rId); +} + + +void OAdoGroup::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + if(m_aGroup.IsValid()) + { + + switch(nHandle) + { + case PROPERTY_ID_NAME: + { + OUString aVal; + rValue >>= aVal; + m_aGroup.put_Name(aVal); + } + break; + } + } +} + +void OAdoGroup::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const +{ + if(m_aGroup.IsValid()) + { + switch(nHandle) + { + case PROPERTY_ID_NAME: + rValue <<= m_aGroup.get_Name(); + break; + } + } +} + + +sal_Int32 SAL_CALL OAdoGroup::getPrivileges( const OUString& objName, sal_Int32 objType ) +{ + return MapRight(m_aGroup.GetPermissions(objName,MapObjectType(objType))); +} + +sal_Int32 SAL_CALL OAdoGroup::getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) +{ + RightsEnum eNum = m_aGroup.GetPermissions(objName,MapObjectType(objType)); + if(eNum & adRightWithGrant) + return MapRight(eNum); + return 0; +} + +void SAL_CALL OAdoGroup::grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) +{ + m_aGroup.SetPermissions(objName,MapObjectType(objType),adAccessGrant,Map2Right(objPrivileges)); +} + +void SAL_CALL OAdoGroup::revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) +{ + m_aGroup.SetPermissions(objName,MapObjectType(objType),adAccessDeny,Map2Right(objPrivileges)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AGroups.cxx b/connectivity/source/drivers/ado/AGroups.cxx new file mode 100644 index 000000000..211f34f6b --- /dev/null +++ b/connectivity/source/drivers/ado/AGroups.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ado/AGroups.hxx> +#include <ado/AGroup.hxx> +#include <ado/ATable.hxx> +#include <ado/AConnection.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <connectivity/sdbcx/IRefreshable.hxx> +#include <TConnection.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> + +using namespace comphelper; +using namespace connectivity; +using namespace connectivity::ado; +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::container; + + +sdbcx::ObjectType OGroups::createObject(const OUString& _rName) +{ + return new OAdoGroup(m_pCatalog,isCaseSensitive(),_rName); +} + +void OGroups::impl_refresh() +{ + m_aCollection.Refresh(); +} + +Reference< XPropertySet > OGroups::createDescriptor() +{ + return new OAdoGroup(m_pCatalog,isCaseSensitive()); +} + +// XAppend +sdbcx::ObjectType OGroups::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + OAdoGroup* pGroup = getUnoTunnelImplementation<OAdoGroup>(descriptor); + if ( pGroup == nullptr ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_GROUP_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + + m_aCollection.Append( pGroup->getImpl() ); + return createObject( _rForName ); +} + +// XDrop +void OGroups::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + m_aCollection.Delete(_sElementName); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AIndex.cxx b/connectivity/source/drivers/ado/AIndex.cxx new file mode 100644 index 000000000..61a047bc9 --- /dev/null +++ b/connectivity/source/drivers/ado/AIndex.cxx @@ -0,0 +1,124 @@ +/* -*- 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 <ado/AIndex.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <ado/AColumns.hxx> +#include <TConnection.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> + +using namespace ::comphelper; + +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + + +OAdoIndex::OAdoIndex(bool _bCase,OConnection* _pConnection,ADOIndex* _pIndex) + : sdbcx::OIndex(OUString(),OUString(),false,false,false,_bCase) + ,m_pConnection(_pConnection) +{ + construct(); + m_aIndex = WpADOIndex(_pIndex); + fillPropertyValues(); +} + +OAdoIndex::OAdoIndex(bool _bCase,OConnection* _pConnection) + : sdbcx::OIndex(_bCase) + ,m_pConnection(_pConnection) +{ + construct(); + m_aIndex.Create(); +} + + +void OAdoIndex::refreshColumns() +{ + ::std::vector< OUString> aVector; + + WpADOColumns aColumns; + if ( m_aIndex.IsValid() ) + { + aColumns = m_aIndex.get_Columns(); + aColumns.fillElementNames(aVector); + } + + if ( m_pColumns ) + m_pColumns->reFill(aVector); + else + m_pColumns.reset(new OColumns(*this, m_aMutex, aVector, aColumns, isCaseSensitive(), m_pConnection)); +} + + +Sequence< sal_Int8 > OAdoIndex::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OAdoIndex::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OAdoIndex>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : sdbcx::OIndex::getSomething(rId); +} + +void SAL_CALL OAdoIndex::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + if(m_aIndex.IsValid()) + { + switch(nHandle) + { + case PROPERTY_ID_NAME: + { + OUString aVal; + rValue >>= aVal; + m_aIndex.put_Name(aVal); + } + break; + case PROPERTY_ID_CATALOG: + { + OUString aVal; + rValue >>= aVal; + m_aIndex.put_Name(aVal); + } + break; + case PROPERTY_ID_ISUNIQUE: + m_aIndex.put_Unique(getBOOL(rValue)); + break; + case PROPERTY_ID_ISPRIMARYKEYINDEX: + m_aIndex.put_PrimaryKey(getBOOL(rValue)); + break; + case PROPERTY_ID_ISCLUSTERED: + m_aIndex.put_Clustered(getBOOL(rValue)); + break; + } + } + sdbcx::OIndex::setFastPropertyValue_NoBroadcast(nHandle,rValue); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AIndexes.cxx b/connectivity/source/drivers/ado/AIndexes.cxx new file mode 100644 index 000000000..616cd863a --- /dev/null +++ b/connectivity/source/drivers/ado/AIndexes.cxx @@ -0,0 +1,82 @@ +/* -*- 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 <ado/AIndexes.hxx> +#include <ado/AIndex.hxx> +#include <ado/AConnection.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/IndexType.hpp> +#include <TConnection.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> + +using namespace ::comphelper; + + +using namespace connectivity; +using namespace connectivity::ado; +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::container; + +sdbcx::ObjectType OIndexes::createObject(const OUString& _rName) +{ + return new OAdoIndex(isCaseSensitive(),m_pConnection,m_aCollection.GetItem(_rName)); +} + +void OIndexes::impl_refresh() +{ + m_aCollection.Refresh(); +} + +Reference< XPropertySet > OIndexes::createDescriptor() +{ + return new OAdoIndex(isCaseSensitive(),m_pConnection); +} + +// XAppend +sdbcx::ObjectType OIndexes::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + OAdoIndex* pIndex = getUnoTunnelImplementation<OAdoIndex>(descriptor); + if ( pIndex == nullptr ) + m_pConnection->throwGenericSQLException( STR_INVALID_INDEX_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + + ADOIndexes* pIndexes = m_aCollection; + if ( FAILED( pIndexes->Append( OLEVariant( _rForName ), OLEVariant( pIndex->getImpl() ) ) ) ) + { + ADOS::ThrowException(*m_pConnection->getConnection(),static_cast<XTypeProvider*>(this)); + m_pConnection->throwGenericSQLException( STR_INVALID_INDEX_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + } + + return new OAdoIndex(isCaseSensitive(),m_pConnection,pIndex->getImpl()); +} + +// XDrop +void OIndexes::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + m_aCollection.Delete(_sElementName); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AKey.cxx b/connectivity/source/drivers/ado/AKey.cxx new file mode 100644 index 000000000..764765b35 --- /dev/null +++ b/connectivity/source/drivers/ado/AKey.cxx @@ -0,0 +1,137 @@ +/* -*- 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 <ado/AKey.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <ado/AColumns.hxx> +#include <ado/AConnection.hxx> + +using namespace connectivity::ado; +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::sdbcx; + + +OAdoKey::OAdoKey(bool _bCase,OConnection* _pConnection, ADOKey* _pKey) + : OKey_ADO(_bCase) + ,m_pConnection(_pConnection) +{ + construct(); + m_aKey = WpADOKey(_pKey); + fillPropertyValues(); +} + +OAdoKey::OAdoKey(bool _bCase,OConnection* _pConnection) + : OKey_ADO(_bCase) + ,m_pConnection(_pConnection) +{ + construct(); + m_aKey.Create(); +} + +void OAdoKey::refreshColumns() +{ + ::std::vector< OUString> aVector; + + WpADOColumns aColumns; + if ( m_aKey.IsValid() ) + { + aColumns = m_aKey.get_Columns(); + aColumns.fillElementNames(aVector); + } + + if(m_pColumns) + m_pColumns->reFill(aVector); + else + m_pColumns.reset(new OColumns(*this, m_aMutex, aVector, aColumns, isCaseSensitive(), m_pConnection)); +} + +Sequence< sal_Int8 > OAdoKey::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OAdoKey::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OAdoKey>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : OKey_ADO::getSomething(rId); +} + +void OAdoKey::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + if(m_aKey.IsValid()) + { + switch(nHandle) + { + case PROPERTY_ID_NAME: + { + OUString aVal; + rValue >>= aVal; + m_aKey.put_Name(aVal); + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + } + break; + case PROPERTY_ID_TYPE: + { + sal_Int32 nVal=0; + rValue >>= nVal; + m_aKey.put_Type(Map2KeyRule(nVal)); + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + } + break; + case PROPERTY_ID_REFERENCEDTABLE: + { + OUString aVal; + rValue >>= aVal; + m_aKey.put_RelatedTable(aVal); + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + } + break; + case PROPERTY_ID_UPDATERULE: + { + sal_Int32 nVal=0; + rValue >>= nVal; + m_aKey.put_UpdateRule(Map2Rule(nVal)); + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + } + break; + case PROPERTY_ID_DELETERULE: + { + sal_Int32 nVal=0; + rValue >>= nVal; + m_aKey.put_DeleteRule(Map2Rule(nVal)); + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + } + break; + } + } + OKey_ADO::setFastPropertyValue_NoBroadcast(nHandle,rValue); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AKeys.cxx b/connectivity/source/drivers/ado/AKeys.cxx new file mode 100644 index 000000000..19027e79f --- /dev/null +++ b/connectivity/source/drivers/ado/AKeys.cxx @@ -0,0 +1,97 @@ +/* -*- 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 <ado/AKeys.hxx> +#include <ado/AKey.hxx> +#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 <ado/AConnection.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <ado/Awrapado.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::ado; +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::sdbcx; +using namespace com::sun::star::container; + +sdbcx::ObjectType OKeys::createObject(const OUString& _rName) +{ + return new OAdoKey(isCaseSensitive(),m_pConnection,m_aCollection.GetItem(_rName)); +} + +void OKeys::impl_refresh() +{ + m_aCollection.Refresh(); +} + +Reference< XPropertySet > OKeys::createDescriptor() +{ + return new OAdoKey(isCaseSensitive(),m_pConnection); +} + +// XAppend +sdbcx::ObjectType OKeys::appendObject( const OUString&, const Reference< XPropertySet >& descriptor ) +{ + OAdoKey* pKey = getUnoTunnelImplementation<OAdoKey>( descriptor ); + if ( pKey == nullptr) + m_pConnection->throwGenericSQLException( STR_INVALID_KEY_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + + // To pass as column parameter to Key's Append method + OLEVariant vOptional; + vOptional.setNoArg(); + + OAdoKey::Map2KeyRule(getINT32(descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))); + + WpADOKey aKey = pKey->getImpl(); + OUString sName = aKey.get_Name(); + if(!sName.getLength()) + aKey.put_Name("PrimaryKey"); + + ADOKeys* pKeys = m_aCollection; + if ( FAILED(pKeys->Append(OLEVariant(static_cast<ADOKey*>(aKey)), + adKeyPrimary, // must be every time adKeyPrimary + vOptional)) ) + { + ADOS::ThrowException(*m_pConnection->getConnection(),static_cast<XTypeProvider*>(this)); + // just make sure that an SQLExceptionis thrown here + m_pConnection->throwGenericSQLException( STR_INVALID_KEY_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + } + + return new OAdoKey(isCaseSensitive(),m_pConnection,pKey->getImpl()); +} + +// XDrop +void OKeys::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + if(!m_aCollection.Delete(OLEVariant(_sElementName).getString())) + ADOS::ThrowException(*m_pConnection->getConnection(),static_cast<XTypeProvider*>(this)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/APreparedStatement.cxx b/connectivity/source/drivers/ado/APreparedStatement.cxx new file mode 100644 index 000000000..ecd4ed538 --- /dev/null +++ b/connectivity/source/drivers/ado/APreparedStatement.cxx @@ -0,0 +1,460 @@ +/* -*- 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/sqlparse.hxx> +#include <ado/APreparedStatement.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <ado/AResultSetMetaData.hxx> +#include <ado/AResultSet.hxx> +#include <ado/ADriver.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <strings.hrc> + +#include <limits> + +#define CHECK_RETURN(x) \ + if(!x) \ + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + +#ifdef max +# undef max +#endif + +using namespace connectivity::ado; +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::util; + +IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.APreparedStatement","com.sun.star.sdbc.PreparedStatement"); + +OPreparedStatement::OPreparedStatement( OConnection* _pConnection, const OUString& sql) + : OStatement_Base( _pConnection ) +{ + osl_atomic_increment( &m_refCount ); + + OSQLParser aParser(comphelper::getComponentContext(_pConnection->getDriver()->getORB())); + OUString sErrorMessage; + OUString sNewSql; + std::unique_ptr<OSQLParseNode> pNode = aParser.parseTree(sErrorMessage,sql); + if(pNode) + { // special handling for parameters + // we recursive replace all occurrences of ? in the statement and + // replace them with name like "parame" */ + sal_Int32 nParameterCount = 0; + replaceParameterNodeName(pNode.get(), "parame", nParameterCount); + pNode->parseNodeToStr( sNewSql, _pConnection ); + } + else + sNewSql = sql; + CHECK_RETURN(m_Command.put_CommandText(sNewSql)) + CHECK_RETURN(m_Command.put_Prepared(VARIANT_TRUE)) + m_pParameters = m_Command.get_Parameters(); + m_pParameters->AddRef(); + m_pParameters->Refresh(); + + osl_atomic_decrement( &m_refCount ); +} + +OPreparedStatement::~OPreparedStatement() +{ + if (m_pParameters) + { + OSL_FAIL( "OPreparedStatement::~OPreparedStatement: not disposed!" ); + m_pParameters->Release(); + m_pParameters = nullptr; + } +} + +Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType ) +{ + Any aRet = OStatement_Base::queryInterface(rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface( rType, + static_cast< XPreparedStatement*>(this), + static_cast< XParameters*>(this), + static_cast< XResultSetMetaDataSupplier*>(this)); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<XPreparedStatement>::get(), + cppu::UnoType<XParameters>::get(), + cppu::UnoType<XResultSetMetaDataSupplier>::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_Base::getTypes()); +} + +Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( ) +{ + if(!m_xMetaData.is() && m_RecordSet.IsValid()) + m_xMetaData = new OResultSetMetaData(m_RecordSet); + return m_xMetaData; +} + +void OPreparedStatement::disposing() +{ + m_xMetaData.clear(); + if (m_pParameters) + { + m_pParameters->Release(); + m_pParameters = nullptr; + } + OStatement_Base::disposing(); +} + +void SAL_CALL OPreparedStatement::close( ) +{ + + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + } + dispose(); + +} + +sal_Bool SAL_CALL OPreparedStatement::execute( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + SQLWarning warning; + clearWarnings (); + + // Call SQLExecute + try { + ADORecordset* pSet=nullptr; + CHECK_RETURN(m_Command.Execute(m_RecordsAffected,m_Parameters,adCmdUnknown,&pSet)) + m_RecordSet = WpADORecordset(pSet); + } + catch (SQLWarning& ex) + { + // Save pointer to warning and save with ResultSet + // object once it is created. + + warning = ex; + } + return m_RecordSet.IsValid(); +} + +sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + ADORecordset* pSet=nullptr; + CHECK_RETURN(m_Command.Execute(m_RecordsAffected,m_Parameters,adCmdUnknown,&pSet)) + if ( VT_ERROR == m_RecordsAffected.getType() ) + { + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + // to be sure that we get the error really thrown + throw SQLException(); + } + m_RecordSet = WpADORecordset(pSet); + return m_RecordsAffected.getInt32(); +} + +void OPreparedStatement::setParameter(sal_Int32 parameterIndex, const DataTypeEnum& _eType, + sal_Int32 _nSize,const OLEVariant& Val) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + sal_Int32 nCount = 0; + m_pParameters->get_Count(&nCount); + if(nCount < (parameterIndex-1)) + { + OUString sDefaultName = "parame" + OUString::number(parameterIndex); + ADOParameter* pParam = m_Command.CreateParameter(sDefaultName,_eType,adParamInput,_nSize,Val); + if(pParam) + { + m_pParameters->Append(pParam); + } + } + else + { + ADOParameter* pParam = nullptr; + m_pParameters->get_Item(OLEVariant(sal_Int32(parameterIndex-1)),&pParam); + WpADOParameter aParam(pParam); + if(pParam) + { + DataTypeEnum eType = aParam.GetADOType(); + if ( _eType != eType && _eType != adDBTimeStamp ) + { + aParam.put_Type(_eType); + eType = _eType; + aParam.put_Size(_nSize); + } + + if ( adVarBinary == eType && aParam.GetAttributes() == adParamLong ) + { + aParam.AppendChunk(Val); + } + else + CHECK_RETURN(aParam.PutValue(Val)); + } + } + ADOS::ThrowException(*m_pConnection->getConnection(),*this); +} + +void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ + setParameter( parameterIndex, adLongVarWChar, std::numeric_limits< sal_Int32 >::max(), x ); +} + +Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + return static_cast<Reference< XConnection >>(m_pConnection); +} + +Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + // first clear the old things + m_xMetaData.clear(); + disposeResultSet(); + if(m_RecordSet.IsValid()) + m_RecordSet.Close(); + m_RecordSet.clear(); + + // then create the new ones + m_RecordSet.Create(); + OLEVariant aCmd; + aCmd.setIDispatch(m_Command); + OLEVariant aCon; + aCon.setNoArg(); + CHECK_RETURN(m_RecordSet.put_CacheSize(m_nFetchSize)) + CHECK_RETURN(m_RecordSet.put_MaxRecords(m_nMaxRows)) + CHECK_RETURN(m_RecordSet.Open(aCmd,aCon,m_eCursorType,m_eLockType,adOpenUnspecified)) + CHECK_RETURN(m_RecordSet.get_CacheSize(m_nFetchSize)) + CHECK_RETURN(m_RecordSet.get_MaxRecords(m_nMaxRows)) + CHECK_RETURN(m_RecordSet.get_CursorType(m_eCursorType)) + CHECK_RETURN(m_RecordSet.get_LockType(m_eLockType)) + + OResultSet* pSet = new OResultSet(m_RecordSet,this); + Reference< XResultSet > xRs = pSet; + pSet->construct(); + pSet->setMetaData(getMetaData()); + m_xResultSet = WeakReference<XResultSet>(xRs); + + return xRs; +} + +void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) +{ + setParameter(parameterIndex,adBoolean,sizeof(x),bool(x)); +} + +void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x ) +{ + setParameter(parameterIndex,adTinyInt,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const Date& x ) +{ + setParameter(parameterIndex,adDBDate,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x ) +{ + setParameter(parameterIndex,adDBTime,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const DateTime& x ) +{ + setParameter(parameterIndex,adDBTimeStamp,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) +{ + setParameter(parameterIndex,adDouble,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) +{ + setParameter(parameterIndex,adSingle,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) +{ + setParameter(parameterIndex,adInteger,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) +{ + setParameter(parameterIndex,adBigInt,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/ ) +{ + OLEVariant aVal; + aVal.setNull(); + setParameter(parameterIndex,adEmpty,0,aVal); +} + +void SAL_CALL OPreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setClob", *this ); +} + +void SAL_CALL OPreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setBlob", *this ); +} + +void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setArray", *this ); +} + +void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setRef", *this ); +} + +void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) +{ + switch(sqlType) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + setString(parameterIndex,::comphelper::getString(x)); + break; + default: + ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); + break; + } +} + +void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ ) +{ + setNull(parameterIndex,sqlType); +} + +void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) +{ + if(!::dbtools::implSetObject(this,parameterIndex,x)) + { + const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution( + STR_UNKNOWN_PARA_TYPE, + "$position$", OUString::number(parameterIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } +} + +void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) +{ + setParameter(parameterIndex,adSmallInt,sizeof(x),x); +} + +void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) +{ + setParameter(parameterIndex,adVarBinary,sizeof(sal_Int8)*x.getLength(),x); +} + +void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 /*parameterIndex*/, const Reference< css::io::XInputStream >& /*x*/, sal_Int32 /*length*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setCharacterStream", *this ); +} + +void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + if(x.is()) + { + Sequence< sal_Int8 > aData; + x->readBytes(aData,length); + setBytes(parameterIndex,aData); + } +} + +void SAL_CALL OPreparedStatement::clearParameters( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + if(m_pParameters) + { + sal_Int32 nCount = 0; + m_pParameters->get_Count(&nCount); + OLEVariant aVal; + aVal.setEmpty(); + for(sal_Int32 i=0;i<nCount;++i) + { + ADOParameter* pParam = nullptr; + m_pParameters->get_Item(OLEVariant(i),&pParam); + WpADOParameter aParam(pParam); + if(pParam) + { + CHECK_RETURN(aParam.PutValue(aVal)); + } + } + } +} + +void SAL_CALL OPreparedStatement::acquire() throw() +{ + OStatement_Base::acquire(); +} + +void SAL_CALL OPreparedStatement::release() throw() +{ + OStatement_Base::release(); +} + +void OPreparedStatement::replaceParameterNodeName(OSQLParseNode const * _pNode, + const OUString& _sDefaultName, + sal_Int32& _rParameterCount) +{ + sal_Int32 nCount = _pNode->count(); + for(sal_Int32 i=0;i < nCount;++i) + { + OSQLParseNode* pChildNode = _pNode->getChild(i); + if(SQL_ISRULE(pChildNode,parameter) && pChildNode->count() == 1) + { + OSQLParseNode* pNewNode = new OSQLParseNode(OUString(":") ,SQLNodeType::Punctuation,0); + delete pChildNode->replace(pChildNode->getChild(0),pNewNode); + OUString sParameterName = _sDefaultName + OUString::number(++_rParameterCount); + pChildNode->append(new OSQLParseNode( sParameterName,SQLNodeType::Name,0)); + } + else + replaceParameterNodeName(pChildNode,_sDefaultName,_rParameterCount); + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AResultSet.cxx b/connectivity/source/drivers/ado/AResultSet.cxx new file mode 100644 index 000000000..dae0f91ef --- /dev/null +++ b/connectivity/source/drivers/ado/AResultSet.cxx @@ -0,0 +1,1155 @@ +/* -*- 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 <ado/AResultSet.hxx> +#include <ado/AResultSetMetaData.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbc/IndexType.hpp> +#include <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <comphelper/property.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/seqstream.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> + +using namespace ::comphelper; + + +#include <oledb.h> + +#define CHECK_RETURN(x) \ + if(!SUCCEEDED(x)) \ + ADOS::ThrowException(*m_pStmt->m_pConnection->getConnection(),*this); + +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + + +// IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.AResultSet","com.sun.star.sdbc.ResultSet"); +OUString SAL_CALL OResultSet::getImplementationName( ) +{ + return "com.sun.star.sdbcx.ado.ResultSet"; +} + +css::uno::Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames( ) +{ + return {"com.sun.star.sdbc.ResultSet","com.sun.star.sdbcx.ResultSet"}; +} + +sal_Bool SAL_CALL OResultSet::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +OResultSet::OResultSet(ADORecordset* _pRecordSet,OStatement_Base* pStmt) : OResultSet_BASE(m_aMutex) + ,OPropertySetHelper(OResultSet_BASE::rBHelper) + ,m_pRecordSet(_pRecordSet) + ,m_pStmt(pStmt) + ,m_xStatement(*pStmt) + ,m_nRowPos(0) + ,m_bEOF(false) + ,m_bOnFirstAfterOpen(false) +{ +} + +OResultSet::OResultSet(ADORecordset* _pRecordSet) : OResultSet_BASE(m_aMutex) + ,OPropertySetHelper(OResultSet_BASE::rBHelper) + ,m_pRecordSet(_pRecordSet) + ,m_pStmt(nullptr) + ,m_nRowPos(0) + ,m_bEOF(false) + ,m_bOnFirstAfterOpen(false) +{ +} + +void OResultSet::construct() +{ + osl_atomic_increment( &m_refCount ); + if (!m_pRecordSet) + { + OSL_FAIL( "OResultSet::construct: no RecordSet!" ); + Reference< XInterface > xInt( *this ); + osl_atomic_decrement( &m_refCount ); + ::dbtools::throwFunctionSequenceException( xInt ); + } + m_pRecordSet->AddRef(); + VARIANT_BOOL bIsAtBOF; + CHECK_RETURN(m_pRecordSet->get_BOF(&bIsAtBOF)) + m_bOnFirstAfterOpen = bIsAtBOF != VARIANT_TRUE; + osl_atomic_decrement( &m_refCount ); +} + +OResultSet::~OResultSet() +{ + if(m_pRecordSet) + m_pRecordSet->Release(); +} + +void OResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + if(m_pRecordSet) + m_pRecordSet->Close(); + m_xStatement.clear(); + m_xMetaData.clear(); +} + +Any SAL_CALL OResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL OResultSet::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(),OResultSet_BASE::getTypes()); +} + + +sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_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 ); + assert(false); + return 0; // Never reached +} +#define BLOCK_SIZE 256 + +Reference< css::io::XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex); + + if((aField.GetAttributes() & adFldLong) == adFldLong) + { + //Copy the data only up to the Actual Size of Field. + sal_Int32 nSize = aField.GetActualSize(); + Sequence<sal_Int8> aData(nSize); + long index = 0; + while(index < nSize) + { + m_aValue = aField.GetChunk(BLOCK_SIZE); + if(m_aValue.isNull()) + break; + UCHAR chData; + for(long index2 = 0;index2 < BLOCK_SIZE;++index2) + { + HRESULT hr = ::SafeArrayGetElement(m_aValue.parray,&index2,&chData); + if(SUCCEEDED(hr)) + { + //Take BYTE by BYTE and advance Memory Location + aData.getArray()[index++] = chData; + } + else + break; + } + } + + return new ::comphelper::SequenceInputStream(aData); + } + // else we ask for a bytesequence + aField.get_Value(m_aValue); + + return m_aValue.isNull() ? nullptr : new ::comphelper::SequenceInputStream(m_aValue.getByteSequence()); +} + +Reference< css::io::XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getCharacterStream", *this ); + return nullptr; +} + +OLEVariant OResultSet::getValue(sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex); + aField.get_Value(m_aValue); + return m_aValue; +} + +sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getBool(); +} + + +sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getInt8(); +} + + +Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getByteSequence(); +} + + +css::util::Date SAL_CALL OResultSet::getDate( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getDate(); +} + + +double SAL_CALL OResultSet::getDouble( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getDouble(); +} + + +float SAL_CALL OResultSet::getFloat( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getFloat(); +} + + +sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getInt32(); +} + + +sal_Int32 SAL_CALL OResultSet::getRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + PositionEnum_Param aPos; + m_pRecordSet->get_AbsolutePosition(&aPos); + return (aPos > 0) ? static_cast<sal_Int32>(aPos) : m_nRowPos; + // return the rowcount from driver if the driver doesn't support this return our count +} + + +sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getLong", *this ); + return sal_Int64(0); +} + + +Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(m_pRecordSet); + return m_xMetaData; +} + +Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getArray", *this ); + return nullptr; +} + + +Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getClob", *this ); + return nullptr; +} + +Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getBlob", *this ); + return nullptr; +} + + +Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRef", *this ); + return nullptr; +} + + +Any SAL_CALL OResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + return getValue(columnIndex).makeAny(); +} + + +sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getInt16(); +} + + +OUString SAL_CALL OResultSet::getString( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getString(); +} + + +css::util::Time SAL_CALL OResultSet::getTime( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getTime(); +} + + +css::util::DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + return getValue(columnIndex).getDateTime(); +} + + +sal_Bool SAL_CALL OResultSet::isAfterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + VARIANT_BOOL bIsAtEOF; + CHECK_RETURN(m_pRecordSet->get_EOF(&bIsAtEOF)) + return bIsAtEOF == VARIANT_TRUE; +} + +sal_Bool SAL_CALL OResultSet::isFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_nRowPos == 1; +} + +sal_Bool SAL_CALL OResultSet::isLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return true; +} + +void SAL_CALL OResultSet::beforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(first()) + m_bOnFirstAfterOpen = !previous(); +} + +void SAL_CALL OResultSet::afterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(last()) + next(); + m_bEOF = true; +} + + +void SAL_CALL OResultSet::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + } + dispose(); +} + + +sal_Bool SAL_CALL OResultSet::first( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(SUCCEEDED(m_pRecordSet->MoveFirst())) + { + m_nRowPos = 1; + m_bOnFirstAfterOpen = false; + return true; + } + return false; +} + + +sal_Bool SAL_CALL OResultSet::last( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + bool bRet = SUCCEEDED(m_pRecordSet->MoveLast()); + if(bRet) + { + m_pRecordSet->get_RecordCount(&m_nRowPos); + m_bOnFirstAfterOpen = false; + } + return bRet; +} + +sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(!row) // absolute with zero not allowed + ::dbtools::throwFunctionSequenceException(*this); + + bool bCheck = true; + if(row < 0) + { + bCheck = SUCCEEDED(m_pRecordSet->MoveLast()); + if ( bCheck ) + { + while(++row < 0 && bCheck) + bCheck = SUCCEEDED(m_pRecordSet->MovePrevious()); + } + } + else + { + first(); + OLEVariant aEmpty; + aEmpty.setNoArg(); + bCheck = SUCCEEDED(m_pRecordSet->Move(row-1,aEmpty)); // move to row -1 because we stand already on the first + if(bCheck) + m_nRowPos = row; + } + if(bCheck) + m_bOnFirstAfterOpen = false; + return bCheck; +} + +sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + OLEVariant aEmpty; + aEmpty.setNoArg(); + sal_Int32 nNewPos = row; + if ( m_bOnFirstAfterOpen && nNewPos > 0 ) + --nNewPos; + bool bRet = SUCCEEDED(m_pRecordSet->Move(row,aEmpty)); + if(bRet) + { + m_nRowPos += row; + m_bOnFirstAfterOpen = false; + } + return bRet; +} + +sal_Bool SAL_CALL OResultSet::previous( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + bool bRet = SUCCEEDED(m_pRecordSet->MovePrevious()); + if(bRet) + { + --m_nRowPos; + m_bOnFirstAfterOpen = false; + } + return bRet; +} + +Reference< XInterface > SAL_CALL OResultSet::getStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_xStatement; +} + + +sal_Bool SAL_CALL OResultSet::rowDeleted( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + sal_Int32 eRec; + m_pRecordSet->get_Status(&eRec); + bool bRet = (RecordStatusEnum(eRec) & adRecDeleted) == adRecDeleted; + if(bRet) + --m_nRowPos; + return bRet; +} + +sal_Bool SAL_CALL OResultSet::rowInserted( ) +{ ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + sal_Int32 eRec; + m_pRecordSet->get_Status(&eRec); + bool bRet = (RecordStatusEnum(eRec) & adRecNew) == adRecNew; + if(bRet) + ++m_nRowPos; + return bRet; +} + +sal_Bool SAL_CALL OResultSet::rowUpdated( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + sal_Int32 eRec; + m_pRecordSet->get_Status(&eRec); + return (RecordStatusEnum(eRec) & adRecModified) == adRecModified; +} + + +sal_Bool SAL_CALL OResultSet::isBeforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + OSL_ENSURE(!m_nRowPos,"OResultSet::isBeforeFirst: Error in setting m_nRowPos!"); + VARIANT_BOOL bIsAtBOF = VARIANT_TRUE; + if(!m_bOnFirstAfterOpen) + { + OSL_ENSURE(!m_nRowPos,"OResultSet::isBeforeFirst: Error in setting m_nRowPos!"); + m_pRecordSet->get_BOF(&bIsAtBOF); + } + return bIsAtBOF == VARIANT_TRUE; +} + + +sal_Bool SAL_CALL OResultSet::next( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + bool bRet = true; + if(m_bOnFirstAfterOpen) + { + m_bOnFirstAfterOpen = false; + ++m_nRowPos; + } + else + { + bRet = SUCCEEDED(m_pRecordSet->MoveNext()); + + if(bRet) + { + VARIANT_BOOL bIsAtEOF; + CHECK_RETURN(m_pRecordSet->get_EOF(&bIsAtEOF)) + bRet = bIsAtEOF != VARIANT_TRUE; + ++m_nRowPos; + } + else + ADOS::ThrowException(*m_pStmt->m_pConnection->getConnection(),*this); + } + + return bRet; +} + + +sal_Bool SAL_CALL OResultSet::wasNull( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_aValue.isNull(); +} + + +void SAL_CALL OResultSet::cancel( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_pRecordSet->Cancel(); +} + +void SAL_CALL OResultSet::clearWarnings( ) +{ +} + +Any SAL_CALL OResultSet::getWarnings( ) +{ + return Any(); +} + +void SAL_CALL OResultSet::insertRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + OLEVariant aEmpty; + aEmpty.setNoArg(); + m_pRecordSet->AddNew(aEmpty,aEmpty); +} + +void SAL_CALL OResultSet::updateRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + OLEVariant aEmpty; + aEmpty.setNoArg(); + m_pRecordSet->Update(aEmpty,aEmpty); +} + +void SAL_CALL OResultSet::deleteRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_pRecordSet->Delete(); + m_pRecordSet->UpdateBatch(adAffectCurrent); +} + + +void SAL_CALL OResultSet::cancelRowUpdates( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_pRecordSet->CancelUpdate(); +} + + +void SAL_CALL OResultSet::moveToInsertRow( ) +{ + // ::osl::MutexGuard aGuard( m_aMutex ); + //checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + // if ( getResultSetConcurrency() == ResultSetConcurrency::READ_ONLY ) + // throw SQLException(); +} + + +void SAL_CALL OResultSet::moveToCurrentRow( ) +{ +} + +void OResultSet::updateValue(sal_Int32 columnIndex,const OLEVariant& x) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + WpADOField aField = ADOS::getField(m_pRecordSet,columnIndex); + aField.PutValue(x); +} + +void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex ) +{ + OLEVariant x; + x.setNull(); + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) +{ + updateValue(columnIndex,bool(x)); +} + +void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + if(!x.is()) + ::dbtools::throwFunctionSequenceException(*this); + + Sequence<sal_Int8> aSeq; + x->readBytes(aSeq,length); + updateBytes(columnIndex,aSeq); +} + +void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + if(!x.is()) + ::dbtools::throwFunctionSequenceException(*this); + + Sequence<sal_Int8> aSeq; + x->readBytes(aSeq,length); + updateBytes(columnIndex,aSeq); +} + +void SAL_CALL OResultSet::refreshRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_pRecordSet->Resync(adAffectCurrent); +} + +void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x ) +{ + if (!::dbtools::implUpdateObject(this, columnIndex, x)) + throw SQLException(); +} + + +void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ ) +{ + if (!::dbtools::implUpdateObject(this, columnIndex, x)) + throw SQLException(); +} + +// XRowLocate +Any SAL_CALL OResultSet::getBookmark( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if(m_nRowPos < static_cast<sal_Int32>(m_aBookmarks.size())) // this bookmark was already fetched + return makeAny(sal_Int32(m_nRowPos-1)); + + OLEVariant aVar; + m_pRecordSet->get_Bookmark(&aVar); + m_aBookmarks.push_back(aVar); + return makeAny(static_cast<sal_Int32>(m_aBookmarks.size()-1)); + +} + +sal_Bool SAL_CALL OResultSet::moveToBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + sal_Int32 nPos = 0; + bookmark >>= nPos; + OSL_ENSURE(nPos >= 0 && nPos < static_cast<sal_Int32>(m_aBookmarks.size()),"Invalid Index for vector"); + if(nPos < 0 || nPos >= static_cast<sal_Int32>(m_aBookmarks.size())) + ::dbtools::throwFunctionSequenceException(*this); + + return SUCCEEDED(m_pRecordSet->Move(0,m_aBookmarks[nPos])); +} + +sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + sal_Int32 nPos = 0; + bookmark >>= nPos; + nPos += rows; + OSL_ENSURE(nPos >= 0 && nPos < static_cast<sal_Int32>(m_aBookmarks.size()),"Invalid Index for vector"); + if(nPos < 0 || nPos >= static_cast<sal_Int32>(m_aBookmarks.size())) + ::dbtools::throwFunctionSequenceException(*this); + return SUCCEEDED(m_pRecordSet->Move(rows,m_aBookmarks[nPos])); +} + +sal_Int32 SAL_CALL OResultSet::compareBookmarks( const Any& bookmark1, const Any& bookmark2 ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nPos1 = 0; + bookmark1 >>= nPos1; + sal_Int32 nPos2 = 0; + bookmark2 >>= nPos2; + if(nPos1 == nPos2) // they should be equal + return css::sdbcx::CompareBookmark::EQUAL; + + OSL_ENSURE((nPos1 >= 0 && nPos1 < static_cast<sal_Int32>(m_aBookmarks.size())) || (nPos1 >= 0 && nPos2 < static_cast<sal_Int32>(m_aBookmarks.size())),"Invalid Index for vector"); + + CompareEnum eNum; + m_pRecordSet->CompareBookmarks(m_aBookmarks[nPos1],m_aBookmarks[nPos2],&eNum); + return static_cast<sal_Int32>(eNum) - 1; +} + +sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + ADOProperties* pProps = nullptr; + m_pRecordSet->get_Properties(&pProps); + WpADOProperties aProps; + aProps.setWithOutAddRef(pProps); + ADOS::ThrowException(*static_cast<OConnection*>(m_pStmt->getConnection().get())->getConnection(),*this); + OSL_ENSURE(aProps.IsValid(),"There are no properties at the connection"); + + WpADOProperty aProp(aProps.GetItem(OUString("Bookmarks Ordered"))); + OLEVariant aVar; + if(aProp.IsValid()) + aVar = aProp.GetValue(); + else + ADOS::ThrowException(*static_cast<OConnection*>(m_pStmt->getConnection().get())->getConnection(),*this); + + bool bValue(false); + if(!aVar.isNull() && !aVar.isEmpty()) + bValue = aVar.getBool(); + return bValue; +} + +sal_Int32 SAL_CALL OResultSet::hashBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + sal_Int32 nPos = 0; + bookmark >>= nPos; + return nPos; +} + +// XDeleteRows +Sequence< sal_Int32 > SAL_CALL OResultSet::deleteRows( const Sequence< Any >& rows ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + OLEVariant aVar; + sal_Int32 nPos = 0; + + // Create SafeArray Bounds and initialize the array + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = rows.getLength(); + SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + const Any* pBegin = rows.getConstArray(); + const Any* pEnd = pBegin + rows.getLength(); + for(sal_Int32 i=0;pBegin != pEnd ;++pBegin,++i) + { + *pBegin >>= nPos; + SafeArrayPutElement(psa,&i,&m_aBookmarks[nPos]); + } + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + m_pRecordSet->put_Filter(vsa); + m_pRecordSet->Delete(adAffectGroup); + m_pRecordSet->UpdateBatch(adAffectGroup); + + Sequence< sal_Int32 > aSeq(rows.getLength()); + if(first()) + { + sal_Int32* pSeq = aSeq.getArray(); + sal_Int32 i=0; + do + { + OSL_ENSURE(i<aSeq.getLength(),"Index greater than length of sequence"); + m_pRecordSet->get_Status(&pSeq[i]); + if(pSeq[i++] == adRecDeleted) + --m_nRowPos; + } + while(next()); + } + return aSeq; +} + +sal_Int32 OResultSet::getResultSetConcurrency() const +{ + sal_Int32 nValue=ResultSetConcurrency::READ_ONLY; + LockTypeEnum eRet; + if(!SUCCEEDED(m_pRecordSet->get_LockType(&eRet))) + { + switch(eRet) + { + case adLockReadOnly: + nValue = ResultSetConcurrency::READ_ONLY; + break; + default: + nValue = ResultSetConcurrency::UPDATABLE; + break; + } + } + return nValue; +} + +sal_Int32 OResultSet::getResultSetType() const +{ + sal_Int32 nValue=0; + CursorTypeEnum eRet; + if(!SUCCEEDED(m_pRecordSet->get_CursorType(&eRet))) + { + switch(eRet) + { + case adOpenUnspecified: + case adOpenForwardOnly: + nValue = ResultSetType::FORWARD_ONLY; + break; + case adOpenStatic: + case adOpenKeyset: + nValue = ResultSetType::SCROLL_INSENSITIVE; + break; + case adOpenDynamic: + nValue = ResultSetType::SCROLL_SENSITIVE; + break; + } + } + return nValue; +} + +sal_Int32 OResultSet::getFetchDirection() +{ + return FetchDirection::FORWARD; +} + +sal_Int32 OResultSet::getFetchSize() const +{ + sal_Int32 nValue=-1; + m_pRecordSet->get_CacheSize(&nValue); + return nValue; +} + +OUString OResultSet::getCursorName() +{ + return OUString(); +} + + +void OResultSet::setFetchDirection(sal_Int32 /*_par0*/) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "ResultSet::FetchDirection", *this ); +} + +void OResultSet::setFetchSize(sal_Int32 _par0) +{ + m_pRecordSet->put_CacheSize(_par0); +} + +::cppu::IPropertyArrayHelper* OResultSet::createArrayHelper( ) const +{ + Sequence< css::beans::Property > aProps(5); + css::beans::Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), + PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper & OResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool OResultSet::convertFastPropertyValue( + Any & rConvertedValue, + Any & rOldValue, + sal_Int32 nHandle, + const Any& rValue ) +{ + switch(nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + break; + case PROPERTY_ID_FETCHDIRECTION: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection()); + case PROPERTY_ID_FETCHSIZE: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize()); + default: + ; + } + return false; +} + +void OResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + switch(nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw Exception("cannot set prop " + OUString::number(nHandle), nullptr); + break; + case PROPERTY_ID_FETCHDIRECTION: + setFetchDirection(getINT32(rValue)); + break; + case PROPERTY_ID_FETCHSIZE: + setFetchSize(getINT32(rValue)); + break; + default: + ; + } +} + +void OResultSet::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const +{ + switch(nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + { + VARIANT_BOOL bBool; + m_pRecordSet->Supports(adBookmark,&bBool); + rValue <<= (bBool == VARIANT_TRUE); + } + break; + case PROPERTY_ID_CURSORNAME: + rValue <<= getCursorName(); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= getResultSetConcurrency(); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= getResultSetType(); + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= getFetchDirection(); + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= getFetchSize(); + break; + } +} + +void SAL_CALL OResultSet::acquire() throw() +{ + OResultSet_BASE::acquire(); +} + +void SAL_CALL OResultSet::release() throw() +{ + OResultSet_BASE::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AResultSetMetaData.cxx b/connectivity/source/drivers/ado/AResultSetMetaData.cxx new file mode 100644 index 000000000..23983342e --- /dev/null +++ b/connectivity/source/drivers/ado/AResultSetMetaData.cxx @@ -0,0 +1,243 @@ +/* -*- 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 <ado/AResultSetMetaData.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <ado/Awrapado.hxx> +#include <connectivity/dbexception.hxx> + +using namespace connectivity; +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +OResultSetMetaData::OResultSetMetaData( ADORecordset* _pRecordSet) + : m_pRecordSet(_pRecordSet), + m_nColCount(-1) +{ + if ( m_pRecordSet ) + m_pRecordSet->AddRef(); +} + +OResultSetMetaData::~OResultSetMetaData() +{ + if ( m_pRecordSet ) + m_pRecordSet->Release(); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid() && aField.GetActualSize() != -1) + return aField.GetActualSize(); + return 0; +} + + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + return ADOS::MapADOType2Jdbc(aField.GetADOType()); +} + + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount( ) +{ + if(m_nColCount != -1 ) + return m_nColCount; + + if ( !m_pRecordSet ) + return 0; + + ADOFields* pFields = nullptr; + m_pRecordSet->get_Fields(&pFields); + WpOLEAppendCollection<ADOFields, ADOField, WpADOField> aFields(pFields); + m_nColCount = aFields.GetItemCount(); + return m_nColCount; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive( sal_Int32 column ) +{ + bool bRet = false; + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if ( aField.IsValid() ) + { + WpADOProperties aProps( aField.get_Properties() ); + if ( aProps.IsValid() ) + bRet = OTools::getValue( aProps, OUString("ISCASESENSITIVE") ).getBool(); + } + return bRet; +} + + +OUString SAL_CALL OResultSetMetaData::getSchemaName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + + +OUString SAL_CALL OResultSetMetaData::getColumnName( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid()) + return aField.GetName(); + + return OUString(); +} + +OUString SAL_CALL OResultSetMetaData::getTableName( sal_Int32 column ) +{ + OUString sTableName; + + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if ( aField.IsValid() ) + { + WpADOProperties aProps( aField.get_Properties() ); + if ( aProps.IsValid() ) + sTableName = OTools::getValue( aProps, OUString("BASETABLENAME") ).getString(); + } + return sTableName; +} + +OUString SAL_CALL OResultSetMetaData::getCatalogName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +OUString SAL_CALL OResultSetMetaData::getColumnTypeName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +OUString SAL_CALL OResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + return getColumnName(column); +} + +OUString SAL_CALL OResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isCurrency( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid()) + { + return ((aField.GetAttributes() & adFldFixed) == adFldFixed) && (aField.GetADOType() == adCurrency); + } + return false; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + bool bRet = false; + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if ( aField.IsValid() ) + { + WpADOProperties aProps( aField.get_Properties() ); + if ( aProps.IsValid() ) + { + bRet = OTools::getValue( aProps, OUString("ISAUTOINCREMENT") ).getBool(); + } + } + return bRet; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid()) + { + DataTypeEnum eType = aField.GetADOType(); + return !(eType == adUnsignedBigInt || eType == adUnsignedInt || eType == adUnsignedSmallInt || eType == adUnsignedTinyInt); + } + return false; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid()) + return aField.GetPrecision(); + return 0; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid()) + return aField.GetNumericScale(); + return 0; +} + + +sal_Int32 SAL_CALL OResultSetMetaData::isNullable( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid()) + { + return sal_Int32((aField.GetAttributes() & adFldIsNullable) == adFldIsNullable); + } + return sal_Int32(false); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isSearchable( sal_Int32 /*column*/ ) +{ + return true; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isReadOnly( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid()) + { + // return (aField.GetStatus() & adFieldReadOnly) == adFieldReadOnly; + } + return false; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + WpADOField aField = ADOS::getField(m_pRecordSet,column); + if(aField.IsValid()) + { + return (aField.GetAttributes() & adFldUpdatable) == adFldUpdatable; + } + return false; +; +} + +sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 column ) +{ + return isDefinitelyWritable(column); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AStatement.cxx b/connectivity/source/drivers/ado/AStatement.cxx new file mode 100644 index 000000000..01fea934c --- /dev/null +++ b/connectivity/source/drivers/ado/AStatement.cxx @@ -0,0 +1,832 @@ +/* -*- 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 <ado/AStatement.hxx> +#include <ado/AConnection.hxx> +#include <ado/AResultSet.hxx> +#include <comphelper/property.hxx> +#include <osl/thread.h> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <connectivity/dbexception.hxx> +#include <comphelper/types.hxx> + +#undef max + +#include <algorithm> +#include <numeric> + +using namespace ::comphelper; + +#define CHECK_RETURN(x) \ + if(!x) \ + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + + +using namespace connectivity::ado; + + +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 ::std; + +OStatement_Base::OStatement_Base(OConnection* _pConnection ) : OStatement_BASE(m_aMutex) + ,OPropertySetHelper(OStatement_BASE::rBHelper) + ,m_pConnection(_pConnection) + ,m_nMaxRows(0) + ,m_nFetchSize(1) + ,m_eLockType(adLockReadOnly) + ,m_eCursorType(adOpenForwardOnly) +{ + osl_atomic_increment( &m_refCount ); + + m_Command.Create(); + if(m_Command.IsValid()) + m_Command.putref_ActiveConnection(m_pConnection->getConnection()); + else + ADOS::ThrowException(*m_pConnection->getConnection(),*this); + + m_RecordsAffected.setNoArg(); + m_Parameters.setNoArg(); + + m_pConnection->acquire(); + + osl_atomic_decrement( &m_refCount ); +} + +void OStatement_Base::disposeResultSet() +{ + // free the cursor if alive + Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + m_xResultSet.clear(); +} + + +void OStatement_Base::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + + disposeResultSet(); + + if ( m_Command.IsValid() ) + m_Command.putref_ActiveConnection( nullptr ); + m_Command.clear(); + + if ( m_RecordSet.IsValid() ) + m_RecordSet.PutRefDataSource( nullptr ); + m_RecordSet.clear(); + + if (m_pConnection) + m_pConnection->release(); + + OStatement_BASE::disposing(); +} + +void SAL_CALL OStatement_Base::release() throw() +{ + OStatement_BASE::release(); +} + +Any SAL_CALL OStatement_Base::queryInterface( const Type & rType ) +{ + Any aRet = OStatement_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL OStatement_Base::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(),OStatement_BASE::getTypes()); +} + + +void SAL_CALL OStatement_Base::cancel( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + CHECK_RETURN(m_Command.Cancel()) +} + + +void SAL_CALL OStatement_Base::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + } + dispose(); +} + + +void SAL_CALL OStatement::clearBatch( ) +{ + +} + + +void OStatement_Base::reset() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + clearWarnings (); + + if (m_xResultSet.get().is()) + clearMyResultSet(); +} + +// clearMyResultSet +// If a ResultSet was created for this Statement, close it + + +void OStatement_Base::clearMyResultSet () +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + try + { + Reference<XCloseable> xCloseable( + m_xResultSet.get(), css::uno::UNO_QUERY); + if ( xCloseable.is() ) + xCloseable->close(); + } + catch( const DisposedException& ) { } + + m_xResultSet.clear(); +} + +sal_Int32 OStatement_Base::getRowCount () +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + return m_RecordsAffected.getInt32(); +} + +// getPrecision +// Given a SQL type, return the maximum precision for the column. +// Returns -1 if not known + + +sal_Int32 OStatement_Base::getPrecision ( sal_Int32 sqlType) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + sal_Int32 prec = -1; + OTypeInfo aInfo; + aInfo.nType = static_cast<sal_Int16>(sqlType); + if (!m_aTypeInfo.empty()) + { + std::vector<OTypeInfo>::const_iterator aIter = std::find(m_aTypeInfo.begin(),m_aTypeInfo.end(),aInfo); + for(;aIter != m_aTypeInfo.end();++aIter) + { + prec = std::max(prec,(*aIter).nPrecision); + } + } + + return prec; +} + +// setWarning +// Sets the warning + + +void OStatement_Base::setWarning (const SQLWarning &ex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_aLastWarning = ex; +} + +void OStatement_Base::assignRecordSet( ADORecordset* _pRS ) +{ + WpADORecordset aOldRS( m_RecordSet ); + m_RecordSet = WpADORecordset( _pRS ); + + if ( aOldRS.IsValid() ) + aOldRS.PutRefDataSource( nullptr ); + + if ( m_RecordSet.IsValid() ) + m_RecordSet.PutRefDataSource( static_cast<IDispatch*>(m_Command) ); +} + +sal_Bool SAL_CALL OStatement_Base::execute( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + // Reset the statement handle and warning + + reset(); + + try + { + ADORecordset* pSet = nullptr; + CHECK_RETURN(m_Command.put_CommandText(sql)) + CHECK_RETURN(m_Command.Execute(m_RecordsAffected,m_Parameters,adCmdText,&pSet)) + + assignRecordSet( pSet ); + } + catch (SQLWarning& ex) + { + + // Save pointer to warning and save with ResultSet + // object once it is created. + + m_aLastWarning = ex; + } + + return m_RecordSet.IsValid(); +} + +Reference< XResultSet > SAL_CALL OStatement_Base::executeQuery( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + reset(); + + m_xResultSet = WeakReference<XResultSet>(nullptr); + + WpADORecordset aSet; + aSet.Create(); + CHECK_RETURN(m_Command.put_CommandText(sql)) + OLEVariant aCmd; + aCmd.setIDispatch(m_Command); + OLEVariant aCon; + aCon.setNoArg(); + CHECK_RETURN(aSet.put_CacheSize(m_nFetchSize)) + CHECK_RETURN(aSet.put_MaxRecords(m_nMaxRows)) + CHECK_RETURN(aSet.Open(aCmd,aCon,m_eCursorType,m_eLockType,adOpenUnspecified)) + + + CHECK_RETURN(aSet.get_CacheSize(m_nFetchSize)) + CHECK_RETURN(aSet.get_MaxRecords(m_nMaxRows)) + CHECK_RETURN(aSet.get_CursorType(m_eCursorType)) + CHECK_RETURN(aSet.get_LockType(m_eLockType)) + + OResultSet* pSet = new OResultSet(aSet,this); + Reference< XResultSet > xRs = pSet; + pSet->construct(); + + m_xResultSet = WeakReference<XResultSet>(xRs); + + return xRs; +} + + +Reference< XConnection > SAL_CALL OStatement_Base::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + return static_cast<Reference< XConnection >>(m_pConnection); +} + + +Any SAL_CALL OStatement::queryInterface( const Type & rType ) +{ + Any aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this)); + return aRet.hasValue() ? aRet : OStatement_Base::queryInterface(rType); +} + + +void SAL_CALL OStatement::addBatch( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_aBatchVector.push_back(sql); +} + +Sequence< sal_Int32 > SAL_CALL OStatement::executeBatch( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + reset(); + + OUString aBatchSql = std::accumulate(m_aBatchVector.begin(), m_aBatchVector.end(), OUString(), + [](const OUString& rRes, const OUString& rStr) { return rRes + rStr + ";"; }); + sal_Int32 nLen = m_aBatchVector.size(); + + + if ( m_RecordSet.IsValid() ) + m_RecordSet.PutRefDataSource( nullptr ); + m_RecordSet.clear(); + m_RecordSet.Create(); + + CHECK_RETURN(m_Command.put_CommandText(aBatchSql)) + if ( m_RecordSet.IsValid() ) + m_RecordSet.PutRefDataSource(static_cast<IDispatch*>(m_Command)); + + CHECK_RETURN(m_RecordSet.UpdateBatch(adAffectAll)) + + ADORecordset* pSet=nullptr; + Sequence< sal_Int32 > aRet(nLen); + sal_Int32* pArray = aRet.getArray(); + for(sal_Int32 j=0;j<nLen;++j) + { + pSet = nullptr; + OLEVariant aRecordsAffected; + if(m_RecordSet.NextRecordset(aRecordsAffected,&pSet) && pSet) + { + assignRecordSet( pSet ); + + ADO_LONGPTR nValue; + if(m_RecordSet.get_RecordCount(nValue)) + pArray[j] = nValue; + } + } + return aRet; +} + + +sal_Int32 SAL_CALL OStatement_Base::executeUpdate( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + reset(); + + try { + ADORecordset* pSet = nullptr; + CHECK_RETURN(m_Command.put_CommandText(sql)) + CHECK_RETURN(m_Command.Execute(m_RecordsAffected,m_Parameters,adCmdText|adExecuteNoRecords,&pSet)) + } + catch (SQLWarning& ex) { + + // Save pointer to warning and save with ResultSet + // object once it is created. + + m_aLastWarning = ex; + } + if(!m_RecordsAffected.isEmpty() && !m_RecordsAffected.isNull() && m_RecordsAffected.getType() != VT_ERROR) + return m_RecordsAffected.getInt32(); + + return 0; +} + + +Reference< XResultSet > SAL_CALL OStatement_Base::getResultSet( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + return m_xResultSet; +} + + +sal_Int32 SAL_CALL OStatement_Base::getUpdateCount( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + ADO_LONGPTR nRet; + if(m_RecordSet.IsValid() && m_RecordSet.get_RecordCount(nRet)) + return nRet; + return -1; +} + + +sal_Bool SAL_CALL OStatement_Base::getMoreResults( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + SQLWarning warning; + + // clear previous warnings + + clearWarnings (); + + // Call SQLMoreResults + + try + { + ADORecordset* pSet=nullptr; + OLEVariant aRecordsAffected; + if(m_RecordSet.IsValid() && m_RecordSet.NextRecordset(aRecordsAffected,&pSet) && pSet) + assignRecordSet( pSet ); + } + catch (SQLWarning &ex) + { + + // Save pointer to warning and save with ResultSet + // object once it is created. + + warning = ex; + } + return m_RecordSet.IsValid(); +} + + +Any SAL_CALL OStatement_Base::getWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + return makeAny(m_aLastWarning); +} + + +void SAL_CALL OStatement_Base::clearWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_aLastWarning = SQLWarning(); +} + + +sal_Int32 OStatement_Base::getQueryTimeOut() const +{ + return m_Command.get_CommandTimeout(); +} + +sal_Int32 OStatement_Base::getMaxRows() const +{ + ADO_LONGPTR nRet=-1; + if(!(m_RecordSet.IsValid() && m_RecordSet.get_MaxRecords(nRet))) + ::dbtools::throwFunctionSequenceException(nullptr); + return nRet; +} + +sal_Int32 OStatement_Base::getResultSetConcurrency() const +{ + sal_Int32 nValue; + + switch(m_eLockType) + { + case adLockReadOnly: + nValue = ResultSetConcurrency::READ_ONLY; + break; + default: + nValue = ResultSetConcurrency::UPDATABLE; + break; + } + + return nValue; +} + +sal_Int32 OStatement_Base::getResultSetType() const +{ + sal_Int32 nValue=0; + switch(m_eCursorType) + { + case adOpenUnspecified: + case adOpenForwardOnly: + nValue = ResultSetType::FORWARD_ONLY; + break; + case adOpenStatic: + case adOpenKeyset: + nValue = ResultSetType::SCROLL_INSENSITIVE; + break; + case adOpenDynamic: + nValue = ResultSetType::SCROLL_SENSITIVE; + break; + } + return nValue; +} + +sal_Int32 OStatement_Base::getFetchDirection() +{ + return FetchDirection::FORWARD; +} + +sal_Int32 OStatement_Base::getFetchSize() const +{ + return m_nFetchSize; +} + +sal_Int32 OStatement_Base::getMaxFieldSize() +{ + return 0; +} + +OUString OStatement_Base::getCursorName() const +{ + return m_Command.GetName(); +} + +void OStatement_Base::setQueryTimeOut(sal_Int32 seconds) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_Command.put_CommandTimeout(seconds); +} + +void OStatement_Base::setMaxRows(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + m_nMaxRows = _par0; +} + +void OStatement_Base::setResultSetConcurrency(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + switch(_par0) + { + case ResultSetConcurrency::READ_ONLY: + m_eLockType = adLockReadOnly; + break; + default: + m_eLockType = adLockOptimistic; + break; + } +} + +void OStatement_Base::setResultSetType(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + switch(_par0) + { + case ResultSetType::FORWARD_ONLY: + m_eCursorType = adOpenForwardOnly; + break; + case ResultSetType::SCROLL_INSENSITIVE: + m_eCursorType = adOpenKeyset; + break; + case ResultSetType::SCROLL_SENSITIVE: + m_eCursorType = adOpenDynamic; + break; + } +} + +void OStatement_Base::setFetchDirection(sal_Int32 /*_par0*/) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "Statement::FetchDirection", *this ); +} + +void OStatement_Base::setFetchSize(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_nFetchSize = _par0; +} + +void OStatement_Base::setMaxFieldSize(sal_Int32 /*_par0*/) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "Statement::MaxFieldSize", *this ); +} + +void OStatement_Base::setCursorName(const OUString &_par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + m_Command.put_Name(_par0); +} + + +::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const +{ + Sequence< css::beans::Property > aProps(10); + css::beans::Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + + +::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool OStatement_Base::convertFastPropertyValue( + Any & rConvertedValue, + Any & rOldValue, + sal_Int32 nHandle, + const Any& rValue ) +{ + bool bModified = false; + + bool bValidAdoRS = m_RecordSet.IsValid(); + // some of the properties below, when set, are remembered in a member, and applied in the next execute + // For these properties, the record set does not need to be valid to allow setting them. + // For all others (where the values are forwarded to the ADO RS directly), the recordset must be valid. + + try + { + switch(nHandle) + { + case PROPERTY_ID_MAXROWS: + bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, bValidAdoRS ? getMaxRows() : m_nMaxRows ); + break; + + case PROPERTY_ID_RESULTSETTYPE: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetType()); + break; + case PROPERTY_ID_FETCHSIZE: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize()); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetConcurrency()); + break; + case PROPERTY_ID_QUERYTIMEOUT: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getQueryTimeOut()); + break; + case PROPERTY_ID_MAXFIELDSIZE: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxFieldSize()); + break; + case PROPERTY_ID_CURSORNAME: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getCursorName()); + break; + case PROPERTY_ID_FETCHDIRECTION: + bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection()); + break; + } + } + catch( const Exception& ) + { + bModified = true; // will ensure that the property is set + OSL_FAIL( "OStatement_Base::convertFastPropertyValue: caught something strange!" ); + } + return bModified; +} + +void OStatement_Base::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + setQueryTimeOut(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_MAXFIELDSIZE: + setMaxFieldSize(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_MAXROWS: + setMaxRows(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_CURSORNAME: + setCursorName(comphelper::getString(rValue)); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + setResultSetConcurrency(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_RESULTSETTYPE: + setResultSetType(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHDIRECTION: + setFetchDirection(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHSIZE: + setFetchSize(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_ESCAPEPROCESSING: + // return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAsLink); + case PROPERTY_ID_USEBOOKMARKS: + // return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAsLink); + default: + ; + } +} + +void OStatement_Base::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const +{ + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + rValue <<= getQueryTimeOut(); + break; + case PROPERTY_ID_MAXFIELDSIZE: + rValue <<= getMaxFieldSize(); + break; + case PROPERTY_ID_MAXROWS: + rValue <<= getMaxRows(); + break; + case PROPERTY_ID_CURSORNAME: + rValue <<= getCursorName(); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= getResultSetConcurrency(); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= getResultSetType(); + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= getFetchDirection(); + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= getFetchSize(); + break; + case PROPERTY_ID_ESCAPEPROCESSING: + rValue <<= true; + break; + case PROPERTY_ID_USEBOOKMARKS: + default: + ; + } +} + +OStatement::~OStatement() +{ +} +IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.AStatement","com.sun.star.sdbc.Statement"); + +void SAL_CALL OStatement_Base::acquire() throw() +{ + OStatement_BASE::acquire(); +} + +void SAL_CALL OStatement::acquire() throw() +{ + OStatement_Base::acquire(); +} + +void SAL_CALL OStatement::release() throw() +{ + OStatement_Base::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ATable.cxx b/connectivity/source/drivers/ado/ATable.cxx new file mode 100644 index 000000000..209255598 --- /dev/null +++ b/connectivity/source/drivers/ado/ATable.cxx @@ -0,0 +1,229 @@ +/* -*- 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 <ado/ATable.hxx> +#include <ado/AIndexes.hxx> +#include <ado/AColumns.hxx> +#include <ado/AColumn.hxx> +#include <ado/AKeys.hxx> +#include <ado/AConnection.hxx> +#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 <cppuhelper/typeprovider.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <ado/Awrapado.hxx> +#include <TConnection.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> + +using namespace ::comphelper; + +using namespace connectivity; +using namespace connectivity::ado; +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::container; + + +OAdoTable::OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog,_ADOTable* _pTable) + : OTable_TYPEDEF(_pTables,_bCase) + ,m_pCatalog(_pCatalog) +{ + construct(); + m_aTable = WpADOTable(_pTable); + // m_aTable.putref_ParentCatalog(_pCatalog->getCatalog()); + fillPropertyValues(); + +} + +OAdoTable::OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog) + : OTable_TYPEDEF(_pTables,_bCase) + ,m_pCatalog(_pCatalog) +{ + construct(); + m_aTable.Create(); + m_aTable.putref_ParentCatalog(_pCatalog->getCatalog()); + +} + +void SAL_CALL OAdoTable::disposing() +{ + OTable_TYPEDEF::disposing(); + m_aTable.clear(); +} + +void OAdoTable::refreshColumns() +{ + ::std::vector< OUString> aVector; + + WpADOColumns aColumns; + if ( m_aTable.IsValid() ) + { + aColumns = m_aTable.get_Columns(); + aColumns.fillElementNames(aVector); + } + + if(m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns = new OColumns(*this,m_aMutex,aVector,aColumns,isCaseSensitive(),m_pCatalog->getConnection()); +} + +void OAdoTable::refreshKeys() +{ + ::std::vector< OUString> aVector; + + WpADOKeys aKeys; + if(m_aTable.IsValid()) + { + aKeys = m_aTable.get_Keys(); + aKeys.fillElementNames(aVector); + } + + if(m_xKeys) + m_xKeys->reFill(aVector); + else + m_xKeys = new OKeys(*this,m_aMutex,aVector,aKeys,isCaseSensitive(),m_pCatalog->getConnection()); +} + +void OAdoTable::refreshIndexes() +{ + ::std::vector< OUString> aVector; + + WpADOIndexes aIndexes; + if(m_aTable.IsValid()) + { + aIndexes = m_aTable.get_Indexes(); + aIndexes.fillElementNames(aVector); + } + + if(m_xIndexes) + m_xIndexes->reFill(aVector); + else + m_xIndexes = new OIndexes(*this,m_aMutex,aVector,aIndexes,isCaseSensitive(),m_pCatalog->getConnection()); +} + +Sequence< sal_Int8 > OAdoTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OAdoTable::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OAdoTable>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : OTable_TYPEDEF::getSomething(rId); +} + +// XRename +void SAL_CALL OAdoTable::rename( const OUString& newName ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE_TYPEDEF::rBHelper.bDisposed); + + m_aTable.put_Name(newName); + ADOS::ThrowException(*(m_pCatalog->getConnection()->getConnection()),*this); + + OTable_TYPEDEF::rename(newName); +} + +Reference< XDatabaseMetaData> OAdoTable::getMetaData() const +{ + return m_pCatalog->getConnection()->getMetaData(); +} + +// XAlterTable +void SAL_CALL OAdoTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE_TYPEDEF::rBHelper.bDisposed); + + bool bError = true; + OAdoColumn* pColumn = comphelper::getUnoTunnelImplementation<OAdoColumn>(descriptor); + if(pColumn != nullptr) + { + WpADOColumns aColumns = m_aTable.get_Columns(); + bError = !aColumns.Delete(colName); + bError = bError || !aColumns.Append(pColumn->getColumnImpl()); + } + if(bError) + ADOS::ThrowException(*(m_pCatalog->getConnection()->getConnection()),*this); + + m_xColumns->refresh(); + refreshColumns(); +} + +void SAL_CALL OAdoTable::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE_TYPEDEF::rBHelper.bDisposed); + + Reference< XPropertySet > xOld; + m_xColumns->getByIndex(index) >>= xOld; + if(xOld.is()) + alterColumnByName(getString(xOld->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),descriptor); +} + +void OAdoTable::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + if(m_aTable.IsValid()) + { + switch(nHandle) + { + case PROPERTY_ID_NAME: + m_aTable.put_Name(getString(rValue)); + break; + + case PROPERTY_ID_TYPE: + OTools::putValue( m_aTable.get_Properties(), + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), + getString(rValue)); + break; + + case PROPERTY_ID_DESCRIPTION: + OTools::putValue( m_aTable.get_Properties(), + OUString("Description"), + getString(rValue)); + break; + + case PROPERTY_ID_SCHEMANAME: + break; + + default: + throw Exception("unknown prop " + OUString::number(nHandle), nullptr); + } + } + OTable_TYPEDEF::setFastPropertyValue_NoBroadcast(nHandle,rValue); +} + +OUString SAL_CALL OAdoTable::getName() +{ + return m_aTable.get_Name(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ATables.cxx b/connectivity/source/drivers/ado/ATables.cxx new file mode 100644 index 000000000..9ce87634e --- /dev/null +++ b/connectivity/source/drivers/ado/ATables.cxx @@ -0,0 +1,103 @@ +/* -*- 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 <ado/ATables.hxx> +#include <ado/ATable.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <ado/ACatalog.hxx> +#include <ado/AConnection.hxx> +#include <ado/Awrapado.hxx> +#include <TConnection.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/interfacecontainer.h> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> + +using namespace ::cppu; +using namespace connectivity; +using namespace comphelper; +using namespace connectivity::ado; +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::container; + +sdbcx::ObjectType OTables::createObject(const OUString& _rName) +{ + OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid"); + return new OAdoTable(this,isCaseSensitive(),m_pCatalog,m_aCollection.GetItem(_rName)); +} + +void OTables::impl_refresh( ) +{ + OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid"); + m_aCollection.Refresh(); + m_pCatalog->refreshTables(); +} + +Reference< XPropertySet > OTables::createDescriptor() +{ + return new OAdoTable(this,isCaseSensitive(),m_pCatalog); +} + +// XAppend +sdbcx::ObjectType OTables::appendObject( const OUString&, const Reference< XPropertySet >& descriptor ) +{ + OAdoTable* pTable = getUnoTunnelImplementation<OAdoTable>( descriptor ); + if ( pTable == nullptr ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_TABLE_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + + OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid"); + if(!m_aCollection.Append(pTable->getImpl())) + ADOS::ThrowException(*m_pCatalog->getConnection()->getConnection(),static_cast<XTypeProvider*>(this)); + m_aCollection.Refresh(); + + return new OAdoTable(this,isCaseSensitive(),m_pCatalog,pTable->getImpl()); +} + +// XDrop +void OTables::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid"); + if ( !m_aCollection.Delete(_sElementName) ) + ADOS::ThrowException(*m_pCatalog->getConnection()->getConnection(),static_cast<XTypeProvider*>(this)); +} + +void OTables::appendNew(const OUString& _rsNewTable) +{ + OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid"); + m_aCollection.Refresh(); + + insertElement(_rsNewTable,nullptr); + + // notify our container listeners + ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_rsNewTable), Any(), Any()); + OInterfaceIteratorHelper2 aListenerLoop(m_aContainerListeners); + while (aListenerLoop.hasMoreElements()) + static_cast<XContainerListener*>(aListenerLoop.next())->elementInserted(aEvent); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AUser.cxx b/connectivity/source/drivers/ado/AUser.cxx new file mode 100644 index 000000000..724334cea --- /dev/null +++ b/connectivity/source/drivers/ado/AUser.cxx @@ -0,0 +1,193 @@ +/* -*- 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 <ado/AUser.hxx> +#include <ado/ACatalog.hxx> +#include <ado/AGroups.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <ado/AConnection.hxx> +#include <ado/Awrapado.hxx> + +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + + +OAdoUser::OAdoUser(OCatalog* _pParent,bool _bCase, ADOUser* _pUser) + : OUser_TYPEDEF(_bCase) + ,m_pCatalog(_pParent) +{ + construct(); + + if(_pUser) + m_aUser = WpADOUser(_pUser); + else + m_aUser.Create(); +} + +OAdoUser::OAdoUser(OCatalog* _pParent,bool _bCase, const OUString& Name) + : OUser_TYPEDEF(Name,_bCase) + , m_pCatalog(_pParent) +{ + construct(); + m_aUser.Create(); + m_aUser.put_Name(Name); +} + +void OAdoUser::refreshGroups() +{ + ::std::vector< OUString> aVector; + WpADOGroups aGroups(m_aUser.get_Groups()); + aGroups.fillElementNames(aVector); + if(m_pGroups) + m_pGroups->reFill(aVector); + else + m_pGroups.reset(new OGroups(m_pCatalog, m_aMutex, aVector, aGroups, isCaseSensitive())); +} + +Sequence< sal_Int8 > OAdoUser::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OAdoUser::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OAdoUser>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : OUser_TYPEDEF::getSomething(rId); +} + + +void OAdoUser::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + if(m_aUser.IsValid()) + { + + switch(nHandle) + { + case PROPERTY_ID_NAME: + { + OUString aVal; + rValue >>= aVal; + m_aUser.put_Name(aVal); + } + break; + } + } +} + +void OAdoUser::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const +{ + if(m_aUser.IsValid()) + { + switch(nHandle) + { + case PROPERTY_ID_NAME: + rValue <<= m_aUser.get_Name(); + break; + } + } +} + +OUserExtend::OUserExtend(OCatalog* _pParent,bool _bCase, ADOUser* _pUser) + : OAdoUser(_pParent,_bCase,_pUser) +{ +} + +OUserExtend::OUserExtend(OCatalog* _pParent,bool _bCase, const OUString& Name) + : OAdoUser(_pParent,_bCase,Name) +{ +} + + +void OUserExtend::construct() +{ + OUser_TYPEDEF::construct(); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), PROPERTY_ID_PASSWORD,0,&m_Password,::cppu::UnoType<OUString>::get()); +} + +cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const +{ + Sequence< css::beans::Property > aProps; + describeProperties(aProps); + return new cppu::OPropertyArrayHelper(aProps); +} + +cppu::IPropertyArrayHelper & OUserExtend::getInfoHelper() +{ + return *OUserExtend_PROP::getArrayHelper(); +} + +sal_Int32 SAL_CALL OAdoUser::getPrivileges( const OUString& objName, sal_Int32 objType ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed); + + return ADOS::mapAdoRights2Sdbc(m_aUser.GetPermissions(objName, ADOS::mapObjectType2Ado(objType))); +} + +sal_Int32 SAL_CALL OAdoUser::getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed); + + sal_Int32 nRights = 0; + RightsEnum eRights = m_aUser.GetPermissions(objName, ADOS::mapObjectType2Ado(objType)); + if((eRights & adRightWithGrant) == adRightWithGrant) + nRights = ADOS::mapAdoRights2Sdbc(eRights); + ADOS::ThrowException(*m_pCatalog->getConnection()->getConnection(),*this); + return nRights; +} + +void SAL_CALL OAdoUser::grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed); + m_aUser.SetPermissions(objName,ADOS::mapObjectType2Ado(objType),adAccessGrant,RightsEnum(ADOS::mapRights2Ado(objPrivileges))); + ADOS::ThrowException(*m_pCatalog->getConnection()->getConnection(),*this); +} + +void SAL_CALL OAdoUser::revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed); + m_aUser.SetPermissions(objName,ADOS::mapObjectType2Ado(objType),adAccessRevoke,RightsEnum(ADOS::mapRights2Ado(objPrivileges))); + ADOS::ThrowException(*m_pCatalog->getConnection()->getConnection(),*this); +} + +// XUser +void SAL_CALL OAdoUser::changePassword( const OUString& objPassword, const OUString& newPassword ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_TYPEDEF::rBHelper.bDisposed); + m_aUser.ChangePassword(objPassword,newPassword); + ADOS::ThrowException(*m_pCatalog->getConnection()->getConnection(),*this); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AUsers.cxx b/connectivity/source/drivers/ado/AUsers.cxx new file mode 100644 index 000000000..2620e915a --- /dev/null +++ b/connectivity/source/drivers/ado/AUsers.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ado/AUsers.hxx> +#include <ado/AUser.hxx> +#include <ado/ATable.hxx> +#include <ado/AConnection.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <connectivity/sdbcx/IRefreshable.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> + +using namespace comphelper; +using namespace connectivity; +using namespace connectivity::ado; +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::container; + +sdbcx::ObjectType OUsers::createObject(const OUString& _rName) +{ + return new OAdoUser(m_pCatalog,isCaseSensitive(),_rName); +} + +void OUsers::impl_refresh() +{ + m_aCollection.Refresh(); +} + +Reference< XPropertySet > OUsers::createDescriptor() +{ + return new OUserExtend(m_pCatalog,isCaseSensitive()); +} + +// XAppend +sdbcx::ObjectType OUsers::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + OUserExtend* pUser = getUnoTunnelImplementation<OUserExtend>( descriptor ); + if ( pUser == nullptr ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_USER_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + + ADOUsers* pUsers = m_aCollection; + pUsers->Append(OLEVariant(pUser->getImpl()),OLEString(pUser->getPassword()).asBSTR()); + + return createObject( _rForName ); +} + +// XDrop +void OUsers::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + m_aCollection.Delete(_sElementName); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AView.cxx b/connectivity/source/drivers/ado/AView.cxx new file mode 100644 index 000000000..b53c1a026 --- /dev/null +++ b/connectivity/source/drivers/ado/AView.cxx @@ -0,0 +1,94 @@ +/* -*- 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 <ado/AView.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <ado/adoimp.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <ado/Awrapado.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + + +using namespace comphelper; +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +// IMPLEMENT_SERVICE_INFO(OAdoView,"com.sun.star.sdbcx.AView","com.sun.star.sdbcx.View"); + +OAdoView::OAdoView(bool _bCase,ADOView* _pView) : OView_ADO(_bCase,nullptr) +,m_aView(_pView) +{ +} + +Sequence< sal_Int8 > OAdoView::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OAdoView::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OAdoView>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : OView_ADO::getSomething(rId); +} + + +void OAdoView::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const +{ + if(m_aView.IsValid()) + { + switch(nHandle) + { + case PROPERTY_ID_NAME: + rValue <<= m_aView.get_Name(); + break; + case PROPERTY_ID_CATALOGNAME: + break; + case PROPERTY_ID_SCHEMANAME: + // rValue <<= m_aView.get_Type(); + break; + case PROPERTY_ID_COMMAND: + { + OLEVariant aVar; + m_aView.get_Command(aVar); + if(!aVar.isNull() && !aVar.isEmpty()) + { + ADOCommand* pCom = static_cast<ADOCommand*>(aVar.getIDispatch()); + OLEString aBSTR; + pCom->get_CommandText(aBSTR.getAddress()); + rValue <<= aBSTR.asOUString(); + } + } + break; + } + } + else + OView_ADO::getFastPropertyValue(rValue,nHandle); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/AViews.cxx b/connectivity/source/drivers/ado/AViews.cxx new file mode 100644 index 000000000..77cc5abfa --- /dev/null +++ b/connectivity/source/drivers/ado/AViews.cxx @@ -0,0 +1,94 @@ +/* -*- 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 <ado/AViews.hxx> +#include <ado/AView.hxx> +#include <ado/ATables.hxx> +#include <ado/ACatalog.hxx> +#include <ado/AConnection.hxx> +#include <ado/Awrapado.hxx> +#include <TConnection.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> + +using namespace ::comphelper; + +using namespace connectivity; +using namespace connectivity::ado; +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::container; + +sdbcx::ObjectType OViews::createObject(const OUString& _rName) +{ + OAdoView* pView = new OAdoView(isCaseSensitive(),m_aCollection.GetItem(_rName)); + pView->setNew(false); + return pView; +} + +void OViews::impl_refresh( ) +{ + m_aCollection.Refresh(); +} + +Reference< XPropertySet > OViews::createDescriptor() +{ + return new OAdoView(isCaseSensitive()); +} + + +// XAppend +sdbcx::ObjectType OViews::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + OAdoView* pView = getUnoTunnelImplementation<OAdoView>( descriptor ); + if ( pView == nullptr ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_INVALID_VIEW_DESCRIPTOR_ERROR,static_cast<XTypeProvider*>(this) ); + + WpADOCommand aCommand; + aCommand.Create(); + if ( !aCommand.IsValid() ) + m_pCatalog->getConnection()->throwGenericSQLException( STR_VIEW_NO_COMMAND_ERROR,static_cast<XTypeProvider*>(this) ); + + OUString sName( _rForName ); + aCommand.put_Name(sName); + aCommand.put_CommandText(getString(descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND)))); + ADOViews* pViews = m_aCollection; + if(FAILED(pViews->Append(OLEString(sName).asBSTR(),aCommand))) + ADOS::ThrowException(*m_pCatalog->getConnection()->getConnection(),static_cast<XTypeProvider*>(this)); + + OTables* pTables = static_cast<OTables*>(static_cast<OCatalog&>(m_rParent).getPrivateTables()); + if ( pTables ) + pTables->appendNew(sName); + + return createObject( _rForName ); +} + +// XDrop +void OViews::dropObject(sal_Int32 /*_nPos*/,const OUString& _sElementName) +{ + if(!m_aCollection.Delete(_sElementName)) + ADOS::ThrowException(*m_pCatalog->getConnection()->getConnection(),static_cast<XTypeProvider*>(this)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/Aolevariant.cxx b/connectivity/source/drivers/ado/Aolevariant.cxx new file mode 100644 index 000000000..7f740e81d --- /dev/null +++ b/connectivity/source/drivers/ado/Aolevariant.cxx @@ -0,0 +1,745 @@ +/* -*- 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 <ado/Aolevariant.hxx> +#include <connectivity/dbconversion.hxx> +#include <osl/diagnose.h> +#include <o3tl/char16_t2wchar_t.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <resource/sharedresources.hxx> +#include <strings.hrc> +#include <com/sun/star/bridge/oleautomation/Date.hpp> +#include <com/sun/star/bridge/oleautomation/Currency.hpp> +#include <com/sun/star/bridge/oleautomation/SCode.hpp> +#include <com/sun/star/bridge/oleautomation/Decimal.hpp> + +using namespace com::sun::star::beans; +using namespace com::sun::star::uno; +using namespace com::sun::star::bridge::oleautomation; +using namespace connectivity::ado; + +OLEString::OLEString() + :m_sStr(nullptr) +{ +} +OLEString::OLEString(const BSTR& _sBStr) + :m_sStr(_sBStr) +{ +} +OLEString::OLEString(const OUString& _sBStr) +{ + m_sStr = ::SysAllocString(o3tl::toW(_sBStr.getStr())); +} +OLEString::~OLEString() +{ + if(m_sStr) + ::SysFreeString(m_sStr); +} +OLEString& OLEString::operator=(const OUString& _rSrc) +{ + if(m_sStr) + ::SysFreeString(m_sStr); + m_sStr = ::SysAllocString(o3tl::toW(_rSrc.getStr())); + return *this; +} +OLEString& OLEString::operator=(const OLEString& _rSrc) +{ + if(this != &_rSrc) + { + if(m_sStr) + ::SysFreeString(m_sStr); + m_sStr = ::SysAllocString(_rSrc.m_sStr); + } + return *this; +} +OLEString& OLEString::operator=(const BSTR& _rSrc) +{ + if(m_sStr) + ::SysFreeString(m_sStr); + m_sStr = _rSrc; + return *this; +} +OUString OLEString::asOUString() const +{ + return (m_sStr != nullptr) ? OUString(o3tl::toU(LPCOLESTR(m_sStr)),::SysStringLen(m_sStr)) : OUString(); +} +BSTR OLEString::asBSTR() const +{ + return m_sStr; +} +BSTR* OLEString::getAddress() +{ + return &m_sStr; +} +sal_Int32 OLEString::length() const +{ + return (m_sStr != nullptr) ? ::SysStringLen(m_sStr) : 0; +} + +OLEVariant::OLEVariant() +{ + VariantInit(this); +} +OLEVariant::OLEVariant(const VARIANT& varSrc) +{ + ::VariantInit(this); + HRESULT eRet = ::VariantCopy(this, &varSrc); + OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!"); +} +OLEVariant::OLEVariant(const OLEVariant& varSrc) +{ + ::VariantInit(this); + HRESULT eRet = ::VariantCopy(this, static_cast<const VARIANT*>(&varSrc)); + OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!"); +} + +OLEVariant::OLEVariant(bool x) { VariantInit(this); vt = VT_BOOL; boolVal = (x ? VARIANT_TRUE : VARIANT_FALSE);} +OLEVariant::OLEVariant(sal_Int8 n) { VariantInit(this); vt = VT_I1; bVal = n;} +OLEVariant::OLEVariant(sal_Int16 n) { VariantInit(this); vt = VT_I2; intVal = n;} +OLEVariant::OLEVariant(sal_Int32 n) { VariantInit(this); vt = VT_I4; lVal = n;} +OLEVariant::OLEVariant(sal_Int64 x) { VariantInit(this); vt = VT_I4; lVal = static_cast<LONG>(x);} + +OLEVariant::OLEVariant(const OUString& us) +{ + ::VariantInit(this); + vt = VT_BSTR; + bstrVal = SysAllocString(o3tl::toW(us.getStr())); +} +OLEVariant::~OLEVariant() +{ + HRESULT eRet = ::VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); +} // clears all the memory that was allocated before + +OLEVariant::OLEVariant(const css::util::Date& x ) +{ + VariantInit(this); + vt = VT_DATE; + dblVal = ::dbtools::DBTypeConversion::toDouble(x,css::util::Date(30,12,1899)); +} +OLEVariant::OLEVariant(const css::util::Time& x ) +{ + VariantInit(this); + vt = VT_DATE; + dblVal = ::dbtools::DBTypeConversion::toDouble(x); +} +OLEVariant::OLEVariant(const css::util::DateTime& x ) +{ + VariantInit(this); + vt = VT_DATE; + dblVal = ::dbtools::DBTypeConversion::toDouble(x,css::util::Date(30,12,1899)); +} +OLEVariant::OLEVariant(float x) +{ + VariantInit(this); + vt = VT_R4; + fltVal = x; +} +OLEVariant::OLEVariant(const double &x) +{ + VariantInit(this); + vt = VT_R8; + dblVal = x; +} + + +OLEVariant::OLEVariant(IDispatch* pDispInterface) +{ + VariantInit(this); + setIDispatch( pDispInterface ); +} + +OLEVariant::OLEVariant(const css::uno::Sequence< sal_Int8 >& x) +{ + VariantInit(this); + + vt = VT_ARRAY|VT_UI1; + + parray = SafeArrayCreateVector(VT_UI1, 0, x.getLength()); + const sal_Int8* pBegin = x.getConstArray(); + const sal_Int8* pEnd = pBegin + x.getLength(); + + for(sal_Int32 i=0;pBegin != pEnd;++i,++pBegin) + { + sal_Int32 nData = *pBegin; + HRESULT rs = SafeArrayPutElement(parray,&i,&nData); + OSL_ENSURE(S_OK == rs,"Error while copy byte data"); + } +} + +OLEVariant& OLEVariant::operator=(const OLEVariant& varSrc) +{ + HRESULT eRet = ::VariantCopy(this, static_cast<const VARIANT*>(&varSrc)); + OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!"); + return *this; +} +// Assign a const VARIANT& (::VariantCopy handles everything) + +OLEVariant& OLEVariant::operator=(const tagVARIANT& varSrc) +{ + HRESULT eRet = ::VariantCopy(this, &varSrc); + OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!"); + + return *this; +} + +// Assign a const VARIANT* (::VariantCopy handles everything) + +OLEVariant& OLEVariant::operator=(const VARIANT* pSrc) +{ + HRESULT eRet = ::VariantCopy(this, pSrc); + OSL_ENSURE(eRet == S_OK,"Error while copying an ado variant!"); + + return *this; +} + +void OLEVariant::setByte(sal_uInt8 n) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_UI1; + bVal = n; +} +void OLEVariant::setInt16(sal_Int16 n) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_I2; + iVal = n; +} +void OLEVariant::setInt32(sal_Int32 n) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_I4; + lVal = n; +} +void OLEVariant::setFloat(float f) +{ HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_R4; + fltVal = f; +} +void OLEVariant::setDouble(double d) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_R8; + dblVal = d; +} +void OLEVariant::setDate(DATE d) +{ HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_DATE; + date = d; +} +void OLEVariant::setChar(unsigned char a) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_UI1; + bVal = a; +} +void OLEVariant::setCurrency(double aCur) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_CY; + set(aCur*10000); +} +void OLEVariant::setBool(bool b) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_BOOL; + boolVal = b ? VARIANT_TRUE : VARIANT_FALSE; +} +void OLEVariant::setString(const OUString& us) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_BSTR; + bstrVal = ::SysAllocString(o3tl::toW(us.getStr())); +} +void OLEVariant::setNoArg() +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_ERROR; + scode = DISP_E_PARAMNOTFOUND; +} + +void OLEVariant::setNull() +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_NULL; +} +void OLEVariant::setEmpty() +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_EMPTY; +} + +void OLEVariant::setUI1SAFEARRAYPtr(SAFEARRAY* pSafeAr) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = VT_ARRAY|VT_UI1; parray = pSafeAr; +} + +void OLEVariant::setArray(SAFEARRAY* pSafeArray, VARTYPE vtType) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + vt = static_cast<VARTYPE>(VT_ARRAY|vtType); + parray = pSafeArray; +} + +void OLEVariant::setIDispatch(IDispatch* pDispInterface) +{ + HRESULT eRet = VariantClear(this); + OSL_ENSURE(eRet == S_OK,"Error while clearing an ado variant!"); + + vt = VT_DISPATCH; + pdispVal = pDispInterface; + + if ( pDispInterface ) + pDispInterface->AddRef(); +} + + +bool OLEVariant::isNull() const { return (vt == VT_NULL); } +bool OLEVariant::isEmpty() const { return (vt == VT_EMPTY); } + +VARTYPE OLEVariant::getType() const { return vt; } + +css::util::Date OLEVariant::getDate() const +{ + return isNull() ? css::util::Date(30,12,1899) : ::dbtools::DBTypeConversion::toDate(getDateAsDouble(),css::util::Date(30,12,1899)); +} +css::util::Time OLEVariant::getTime() const +{ + return isNull() ? css::util::Time() : ::dbtools::DBTypeConversion::toTime(getDateAsDouble()); +} +css::util::DateTime OLEVariant::getDateTime() const +{ + return isNull() ? css::util::DateTime() : ::dbtools::DBTypeConversion::toDateTime(getDateAsDouble(),css::util::Date(30,12,1899)); +} + +VARIANT_BOOL OLEVariant::VariantBool(bool bEinBoolean) +{ + return (bEinBoolean ? VARIANT_TRUE : VARIANT_FALSE); +} + +void OLEVariant::CHS() +{ + cyVal.Lo ^= sal_uInt32(-1); + cyVal.Hi ^= -1; + cyVal.Lo++; + if( !cyVal.Lo ) + cyVal.Hi++; +} + +void OLEVariant::set(double n) +{ + if( n >= 0 ) + { + cyVal.Hi = static_cast<sal_Int32>(n / 4294967296.0); + cyVal.Lo = static_cast<sal_uInt32>(n - (static_cast<double>(cyVal.Hi) * 4294967296.0)); + } + else { + cyVal.Hi = static_cast<sal_Int32>(-n / 4294967296.0); + cyVal.Lo = static_cast<sal_uInt32>(-n - (static_cast<double>(cyVal.Hi) * 4294967296.0)); + CHS(); + } +} + +OUString OLEVariant::getString() const +{ + if (V_VT(this) == VT_BSTR) + return o3tl::toU(LPCOLESTR(V_BSTR(this))); + + if(isNull()) + return OUString(); + + OLEVariant varDest; + + varDest.ChangeType(VT_BSTR, this); + + return o3tl::toU(LPCOLESTR(V_BSTR(&varDest))); +} + + +void OLEVariant::ChangeType(VARTYPE vartype, const OLEVariant* pSrc) +{ + + // If pDest is NULL, convert type in place + + if (pSrc == nullptr) + pSrc = this; + + if ( ( this != pSrc ) + || ( vartype != V_VT( this ) ) + ) + { + if ( FAILED( ::VariantChangeType( static_cast< VARIANT* >( this ), + static_cast< const VARIANT* >( pSrc ), + 0, + vartype ) ) ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_TYPE_NOT_CONVERT)); + throw css::sdbc::SQLException( + sError, + nullptr, + "S1000", + 1000, + css::uno::Any() + ); + } + } +} + + +css::uno::Sequence< sal_Int8 > OLEVariant::getByteSequence() const +{ + css::uno::Sequence< sal_Int8 > aRet; + if(V_VT(this) == VT_BSTR) + { + OLEString sStr(V_BSTR(this)); + aRet = css::uno::Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(sStr.asBSTR()),sizeof(sal_Unicode)*sStr.length()); + } + else if(!isNull()) + { + SAFEARRAY* pArray = getUI1SAFEARRAYPtr(); + + if(pArray) + { + HRESULT hresult1,hresult2; + long lBound,uBound; + // Verify that the SafeArray is the proper shape. + hresult1 = ::SafeArrayGetLBound(pArray, 1, &lBound); + hresult2 = ::SafeArrayGetUBound(pArray, 1, &uBound); + if ( SUCCEEDED(hresult1) && SUCCEEDED(hresult2) ) + { + long nCount = uBound-lBound+1; + aRet.realloc(nCount); + sal_Int8* pData = aRet.getArray(); + for(long i=0; SUCCEEDED(hresult1) && lBound <= uBound ;++i,++lBound) + { + sal_Int32 nData = 0; + hresult1 = ::SafeArrayGetElement(pArray,&lBound,&nData); + if ( SUCCEEDED(hresult1) ) + { + *pData = static_cast<sal_Int8>(nData); + ++pData; + } + } + } + } + } + + return aRet; +} + +bool OLEVariant::getBool() const +{ + if (V_VT(this) == VT_BOOL) + return V_BOOL(this) == VARIANT_TRUE; + if(isNull()) + return false; + + OLEVariant varDest; + + varDest.ChangeType(VT_BOOL, this); + + return V_BOOL(&varDest) == VARIANT_TRUE; +} + +IUnknown* OLEVariant::getIUnknown() const +{ + if (V_VT(this) == VT_UNKNOWN) + { + return V_UNKNOWN(this); + } + if(isNull()) + return nullptr; + + OLEVariant varDest; + + varDest.ChangeType(VT_UNKNOWN, this); + + V_UNKNOWN(&varDest)->AddRef(); + return V_UNKNOWN(&varDest); +} + +IDispatch* OLEVariant::getIDispatch() const +{ + if (V_VT(this) == VT_DISPATCH) + { + return V_DISPATCH(this); + } + + if(isNull()) + return nullptr; + + OLEVariant varDest; + + varDest.ChangeType(VT_DISPATCH, this); + + V_DISPATCH(&varDest)->AddRef(); + return V_DISPATCH(&varDest); +} + +sal_uInt8 OLEVariant::getByte() const +{ + if (V_VT(this) == VT_UI1) + return V_UI1(this); + + if(isNull()) + return sal_Int8(0); + OLEVariant varDest; + + varDest.ChangeType(VT_UI1, this); + + return V_UI1(&varDest); +} + +sal_Int16 OLEVariant::getInt16() const +{ + if (V_VT(this) == VT_I2) + return V_I2(this); + + if(isNull()) + return sal_Int16(0); + OLEVariant varDest; + + varDest.ChangeType(VT_I2, this); + + return V_I2(&varDest); +} + +sal_Int8 OLEVariant::getInt8() const +{ + if (V_VT(this) == VT_I1) + return V_I1(this); + + if(isNull()) + return sal_Int8(0); + + OLEVariant varDest; + + varDest.ChangeType(VT_I1, this); + + return V_I1(&varDest); +} + +sal_Int32 OLEVariant::getInt32() const +{ + if (V_VT(this) == VT_I4) + return V_I4(this); + + if(isNull()) + return sal_Int32(0); + + OLEVariant varDest; + + varDest.ChangeType(VT_I4, this); + + return V_I4(&varDest); +} + +sal_uInt32 OLEVariant::getUInt32() const +{ + if (V_VT(this) == VT_UI4) + return V_UI4(this); + + if(isNull()) + return sal_uInt32(0); + + OLEVariant varDest; + + varDest.ChangeType(VT_UI4, this); + + return V_UI4(&varDest); +} + +float OLEVariant::getFloat() const +{ + if (V_VT(this) == VT_R4) + return V_R4(this); + + if(isNull()) + return float(0); + OLEVariant varDest; + + varDest.ChangeType(VT_R4, this); + + return V_R4(&varDest); +} + +double OLEVariant::getDouble() const +{ + if (V_VT(this) == VT_R8) + return V_R8(this); + + if(isNull()) + return double(0); + OLEVariant varDest; + + varDest.ChangeType(VT_R8, this); + + return V_R8(&varDest); +} + +double OLEVariant::getDateAsDouble() const +{ + if (V_VT(this) == VT_DATE) + return V_DATE(this); + + if(isNull()) + return double(0); + OLEVariant varDest; + + varDest.ChangeType(VT_DATE, this); + + return V_DATE(&varDest); +} + +CY OLEVariant::getCurrency() const +{ + if (V_VT(this) == VT_CY) + return V_CY(this); + + if(isNull()) + { + CY aVar; + aVar.int64 = sal_Int64(0); + return aVar; + } + OLEVariant varDest; + + varDest.ChangeType(VT_CY, this); + + return V_CY(&varDest); +} + +SAFEARRAY* OLEVariant::getUI1SAFEARRAYPtr() const +{ + if (V_VT(this) == (VT_ARRAY|VT_UI1)) + return V_ARRAY(this); + + if(isNull()) + return nullptr; + OLEVariant varDest; + + varDest.ChangeType((VT_ARRAY|VT_UI1), this); + + return V_ARRAY(&varDest); +} + +css::uno::Any OLEVariant::makeAny() const +{ + css::uno::Any aValue; + switch (V_VT(this)) + { + case VT_EMPTY: + case VT_NULL: + aValue.setValue(nullptr, Type()); + break; + case VT_I2: + aValue.setValue( & iVal, cppu::UnoType<sal_Int16>::get()); + break; + case VT_I4: + aValue.setValue( & lVal, cppu::UnoType<sal_Int32>::get()); + break; + case VT_R4: + aValue.setValue( & fltVal, cppu::UnoType<float>::get()); + break; + case VT_R8: + aValue.setValue(& dblVal, cppu::UnoType<double>::get()); + break; + case VT_CY: + { + Currency cy(cyVal.int64); + aValue <<= cy; + break; + } + case VT_DATE: + { + aValue <<= getDate(); + break; + } + case VT_BSTR: + { + OUString b(o3tl::toU(bstrVal)); + aValue.setValue( &b, cppu::UnoType<decltype(b)>::get()); + break; + } + case VT_BOOL: + { + aValue <<= (boolVal == VARIANT_TRUE); + break; + } + case VT_I1: + aValue.setValue( & cVal, cppu::UnoType<sal_Int8>::get()); + break; + case VT_UI1: // there is no unsigned char in UNO + aValue <<= sal_Int8(bVal); + break; + case VT_UI2: + aValue.setValue( & uiVal, cppu::UnoType<cppu::UnoUnsignedShortType>::get()); + break; + case VT_UI4: + aValue.setValue( & ulVal, cppu::UnoType<sal_uInt32>::get()); + break; + case VT_INT: + aValue.setValue( & intVal, cppu::UnoType<sal_Int32>::get()); + break; + case VT_UINT: + aValue.setValue( & uintVal, cppu::UnoType<sal_uInt32>::get()); + break; + case VT_VOID: + aValue.setValue( nullptr, Type()); + break; + case VT_DECIMAL: + { + Decimal dec; + dec.Scale = decVal.scale; + dec.Sign = decVal.sign; + dec.LowValue = decVal.Lo32; + dec.MiddleValue = decVal.Mid32; + dec.HighValue = decVal.Hi32; + aValue <<= dec; + break; + } + + default: + break; + } + return aValue; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/Aservices.cxx b/connectivity/source/drivers/ado/Aservices.cxx new file mode 100644 index 000000000..0ec3ba953 --- /dev/null +++ b/connectivity/source/drivers/ado/Aservices.cxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ado/ADriver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::ado; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames , + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* ado_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + ODriver::getImplementationName_Static(), + ODriver::getSupportedServiceNames_Static(), + ODriver_CreateInstance, ::cppu::createSingleFactory) + ; + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/Awrapado.cxx b/connectivity/source/drivers/ado/Awrapado.cxx new file mode 100644 index 000000000..1fc664f89 --- /dev/null +++ b/connectivity/source/drivers/ado/Awrapado.cxx @@ -0,0 +1,2153 @@ +/* -*- 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/macros.h> +#include <ado/Awrapado.hxx> +#include <ado/Awrapadox.hxx> +#include <comphelper/types.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +using namespace connectivity::ado; + +void WpADOCatalog::Create() +{ + _ADOCatalog* pCommand; + HRESULT hr = CoCreateInstance(ADOS::CLSID_ADOCATALOG_25, + nullptr, + CLSCTX_INPROC_SERVER, + ADOS::IID_ADOCATALOG_25, + reinterpret_cast<void**>(&pCommand) ); + + + if( !FAILED( hr ) ) + setWithOutAddRef(pCommand); +} + + +WpADOProperties WpADOConnection::get_Properties() const +{ + ADOProperties* pProps=nullptr; + pInterface->get_Properties(&pProps); + WpADOProperties aProps; + aProps.setWithOutAddRef(pProps); + return aProps; +} + +OUString WpADOConnection::GetConnectionString() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_ConnectionString(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +bool WpADOConnection::PutConnectionString(const OUString &aCon) const +{ + assert(pInterface); + OLEString bstr(aCon); + bool bErg = SUCCEEDED(pInterface->put_ConnectionString(bstr.asBSTR())); + + return bErg; +} + +sal_Int32 WpADOConnection::GetCommandTimeout() const +{ + assert(pInterface); + sal_Int32 nRet=0; + pInterface->get_CommandTimeout(&nRet); + return nRet; +} + +void WpADOConnection::PutCommandTimeout(sal_Int32 nRet) +{ + assert(pInterface); + pInterface->put_CommandTimeout(nRet); +} + +sal_Int32 WpADOConnection::GetConnectionTimeout() const +{ + assert(pInterface); + sal_Int32 nRet=0; + pInterface->get_ConnectionTimeout(&nRet); + return nRet; +} + +void WpADOConnection::PutConnectionTimeout(sal_Int32 nRet) +{ + assert(pInterface); + pInterface->put_ConnectionTimeout(nRet); +} + +bool WpADOConnection::Close() +{ + assert(pInterface); + return (SUCCEEDED(pInterface->Close())); +} + +bool WpADOConnection::Execute(const OUString& CommandText,OLEVariant& RecordsAffected,long Options, WpADORecordset** ppiRset) +{ + assert(pInterface); + OLEString sStr1(CommandText); + bool bErg = SUCCEEDED(pInterface->Execute(sStr1.asBSTR(),&RecordsAffected,Options,reinterpret_cast<ADORecordset**>(ppiRset))); + return bErg; +} + +bool WpADOConnection::BeginTrans() +{ + assert(pInterface); + sal_Int32 nIso=0; + return SUCCEEDED(pInterface->BeginTrans(&nIso)); +} + +bool WpADOConnection::CommitTrans( ) +{ + assert(pInterface); + return SUCCEEDED(pInterface->CommitTrans()); +} + +bool WpADOConnection::RollbackTrans( ) +{ + assert(pInterface); + return SUCCEEDED(pInterface->RollbackTrans()); +} + +bool WpADOConnection::Open(const OUString& ConnectionString, const OUString& UserID,const OUString& Password,long Options) +{ + assert(pInterface); + OLEString sStr1(ConnectionString); + OLEString sStr2(UserID); + OLEString sStr3(Password); + bool bErg = SUCCEEDED(pInterface->Open(sStr1.asBSTR(),sStr2.asBSTR(),sStr3.asBSTR(),Options)); + return bErg; +} + +bool WpADOConnection::GetErrors(ADOErrors** pErrors) +{ + assert(pInterface); + return SUCCEEDED(pInterface->get_Errors(pErrors)); +} + +OUString WpADOConnection::GetDefaultDatabase() const +{ + assert(pInterface); + OLEString aBSTR; pInterface->get_DefaultDatabase(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +bool WpADOConnection::PutDefaultDatabase(const OUString& _bstr) +{ + assert(pInterface); + OLEString bstr(_bstr); + bool bErg = SUCCEEDED(pInterface->put_DefaultDatabase(bstr.asBSTR())); + + return bErg; +} + +IsolationLevelEnum WpADOConnection::get_IsolationLevel() const +{ + assert(pInterface); + IsolationLevelEnum eNum=adXactUnspecified; + pInterface->get_IsolationLevel(&eNum); + return eNum; +} + +bool WpADOConnection::put_IsolationLevel(const IsolationLevelEnum& eNum) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_IsolationLevel(eNum)); +} + +sal_Int32 WpADOConnection::get_Attributes() const +{ + assert(pInterface); + sal_Int32 nRet=0; + pInterface->get_Attributes(&nRet); + return nRet; +} + +bool WpADOConnection::put_Attributes(sal_Int32 nRet) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_Attributes(nRet)); +} + +CursorLocationEnum WpADOConnection::get_CursorLocation() const +{ + assert(pInterface); + CursorLocationEnum eNum=adUseNone; + pInterface->get_CursorLocation(&eNum); + return eNum; +} + +bool WpADOConnection::put_CursorLocation(const CursorLocationEnum &eNum) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_CursorLocation(eNum)); +} + +ConnectModeEnum WpADOConnection::get_Mode() const +{ + assert(pInterface); + ConnectModeEnum eNum=adModeUnknown; + pInterface->get_Mode(&eNum); + return eNum; +} + +bool WpADOConnection::put_Mode(const ConnectModeEnum &eNum) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_Mode(eNum)); +} + +OUString WpADOConnection::get_Provider() const +{ + assert(pInterface); + OLEString aBSTR; pInterface->get_Provider(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +bool WpADOConnection::put_Provider(const OUString& _bstr) +{ + assert(pInterface); + OLEString bstr(_bstr); + return SUCCEEDED(pInterface->put_Provider(bstr.asBSTR())); +} + +sal_Int32 WpADOConnection::get_State() const +{ + assert(pInterface); + sal_Int32 nRet=0; + pInterface->get_State(&nRet); + return nRet; +} + +bool WpADOConnection::OpenSchema(SchemaEnum eNum,OLEVariant const & Restrictions,OLEVariant const & SchemaID,ADORecordset**pprset) +{ + assert(pInterface); + return SUCCEEDED(pInterface->OpenSchema(eNum,Restrictions,SchemaID,pprset)); +} + +OUString WpADOConnection::get_Version() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Version(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +bool WpADOCommand::putref_ActiveConnection( WpADOConnection *pCon) +{ + assert(pInterface); + if(pCon) + return SUCCEEDED(pInterface->putref_ActiveConnection(pCon->pInterface)); + else + return SUCCEEDED(pInterface->putref_ActiveConnection(nullptr)); +} + +void WpADOCommand::put_ActiveConnection(/* [in] */ const OLEVariant& vConn) +{ + assert(pInterface); + pInterface->put_ActiveConnection(vConn); +} + +void WpADOCommand::Create() +{ + IClassFactory2* pInterface2 = nullptr; + HRESULT hr = CoGetClassObject( ADOS::CLSID_ADOCOMMAND_21, + CLSCTX_INPROC_SERVER, + nullptr, + IID_IClassFactory2, + reinterpret_cast<void**>(&pInterface2) ); + + if( !FAILED( hr ) ) + { + ADOCommand* pCommand=nullptr; + IUnknown* pOuter=nullptr; + + hr = pInterface2->CreateInstanceLic( pOuter, + nullptr, + ADOS::IID_ADOCOMMAND_21, + ADOS::GetKeyStr().asBSTR(), + reinterpret_cast<void**>(&pCommand)); + + if( !FAILED( hr ) ) + { + operator=(pCommand); + pCommand->Release(); + } + + pInterface2->Release(); + } +} + +sal_Int32 WpADOCommand::get_State() const +{ + assert(pInterface); + sal_Int32 nRet=0; + pInterface->get_State(&nRet); + return nRet; +} + +OUString WpADOCommand::get_CommandText() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_CommandText(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +bool WpADOCommand::put_CommandText(const OUString &aCon) +{ + assert(pInterface); + OLEString bstr(aCon); + bool bErg = SUCCEEDED(pInterface->put_CommandText(bstr.asBSTR())); + + return bErg; +} + +sal_Int32 WpADOCommand::get_CommandTimeout() const +{ + assert(pInterface); + sal_Int32 nRet=0; + pInterface->get_CommandTimeout(&nRet); + return nRet; +} + +void WpADOCommand::put_CommandTimeout(sal_Int32 nRet) +{ + assert(pInterface); + pInterface->put_CommandTimeout(nRet); +} + +bool WpADOCommand::get_Prepared() const +{ + assert(pInterface); + VARIANT_BOOL bPrepared = VARIANT_FALSE; + pInterface->get_Prepared(&bPrepared); + return bPrepared == VARIANT_TRUE; +} + +bool WpADOCommand::put_Prepared(VARIANT_BOOL bPrepared) const +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_Prepared(bPrepared)); +} + +bool WpADOCommand::Execute(OLEVariant& RecordsAffected,OLEVariant& Params,long Options, ADORecordset** ppiRset) +{ + assert(pInterface); + return SUCCEEDED(pInterface->Execute(&RecordsAffected,&Params,Options,ppiRset)); +} + +ADOParameter* WpADOCommand::CreateParameter(const OUString &_bstr,DataTypeEnum Type,ParameterDirectionEnum Direction,long nSize,const OLEVariant &Value) +{ + assert(pInterface); + ADOParameter* pPara = nullptr; + OLEString bstr(_bstr); + bool bErg = SUCCEEDED(pInterface->CreateParameter(bstr.asBSTR(),Type,Direction,nSize,Value,&pPara)); + + return bErg ? pPara : nullptr; +} + +ADOParameters* WpADOCommand::get_Parameters() const +{ + assert(pInterface); + ADOParameters* pPara=nullptr; + pInterface->get_Parameters(&pPara); + return pPara; +} + +bool WpADOCommand::put_CommandType( /* [in] */ CommandTypeEnum lCmdType) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_CommandType(lCmdType)); +} + +CommandTypeEnum WpADOCommand::get_CommandType() const +{ + assert(pInterface); + CommandTypeEnum eNum=adCmdUnspecified; + pInterface->get_CommandType(&eNum); + return eNum; +} + +// returns the name of the field +OUString WpADOCommand::GetName() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +bool WpADOCommand::put_Name(const OUString& Name) +{ + assert(pInterface); + OLEString bstr(Name); + bool bErg = SUCCEEDED(pInterface->put_Name(bstr.asBSTR())); + + return bErg; +} +bool WpADOCommand::Cancel() +{ + assert(pInterface); + return SUCCEEDED(pInterface->Cancel()); +} + +OUString WpADOError::GetDescription() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Description(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +OUString WpADOError::GetSource() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Source(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +sal_Int32 WpADOError::GetNumber() const +{ + assert(pInterface); + sal_Int32 nErrNr=0; + pInterface->get_Number(&nErrNr); + return nErrNr; +} + +OUString WpADOError::GetSQLState() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_SQLState(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +sal_Int32 WpADOError::GetNativeError() const +{ + assert(pInterface); + sal_Int32 nErrNr=0; + pInterface->get_NativeError(&nErrNr); + return nErrNr; +} + +WpADOProperties WpADOField::get_Properties() +{ + assert(pInterface); + ADOProperties* pProps = nullptr; + pInterface->get_Properties(&pProps); + WpADOProperties aProps; + + aProps.setWithOutAddRef(pProps); + return aProps; +} + +sal_Int32 WpADOField::GetActualSize() const +{ + assert(pInterface); + ADO_LONGPTR nActualSize=0; + pInterface->get_ActualSize(&nActualSize); + return nActualSize; +} + +sal_Int32 WpADOField::GetAttributes() const +{ + assert(pInterface); + sal_Int32 eADOSFieldAttributes=0; + pInterface->get_Attributes(&eADOSFieldAttributes); + return eADOSFieldAttributes; +} + +sal_Int32 WpADOField::GetStatus() const +{ + assert(pInterface); + // pInterface->get_Status(&eADOSFieldAttributes); + return 0; +} + +sal_Int32 WpADOField::GetDefinedSize() const +{ + assert(pInterface); + ADO_LONGPTR nDefinedSize=0; + pInterface->get_DefinedSize(&nDefinedSize); + return nDefinedSize; +} + +// returns the name of the field +OUString WpADOField::GetName() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +DataTypeEnum WpADOField::GetADOType() const +{ + assert(pInterface); + DataTypeEnum eType=adEmpty; + pInterface->get_Type(&eType); + return eType; +} + +void WpADOField::get_Value(OLEVariant& aValVar) const +{ + assert(pInterface); + aValVar.setEmpty(); + pInterface->get_Value(&aValVar); +} + +OLEVariant WpADOField::get_Value() const +{ + assert(pInterface); + OLEVariant aValVar; + pInterface->get_Value(&aValVar); + return aValVar; +} + +bool WpADOField::PutValue(const OLEVariant& aVariant) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_Value(aVariant))); +} + +sal_Int32 WpADOField::GetPrecision() const +{ + assert(pInterface); + sal_uInt8 eType=0; + pInterface->get_Precision(&eType); + return eType; +} + +sal_Int32 WpADOField::GetNumericScale() const +{ + assert(pInterface); + sal_uInt8 eType=0; + pInterface->get_NumericScale(&eType); + return eType; +} + +bool WpADOField::AppendChunk(const OLEVariant& Variant) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->AppendChunk(Variant))); +} + +OLEVariant WpADOField::GetChunk(long Length) const +{ + assert(pInterface); + OLEVariant aValVar; + pInterface->GetChunk(Length,&aValVar); + return aValVar; +} + +void WpADOField::GetChunk(long Length,OLEVariant &aValVar) const +{ + assert(pInterface); + pInterface->GetChunk(Length,&aValVar); +} + +OLEVariant WpADOField::GetOriginalValue() const +{ + assert(pInterface); + OLEVariant aValVar; + pInterface->get_OriginalValue(&aValVar); + return aValVar; +} + +void WpADOField::GetOriginalValue(OLEVariant &aValVar) const +{ + assert(pInterface); + pInterface->get_OriginalValue(&aValVar); +} + +OLEVariant WpADOField::GetUnderlyingValue() const +{ + assert(pInterface); + OLEVariant aValVar; + pInterface->get_UnderlyingValue(&aValVar); + return aValVar; +} + +void WpADOField::GetUnderlyingValue(OLEVariant &aValVar) const +{ + assert(pInterface); + pInterface->get_UnderlyingValue(&aValVar); +} + +bool WpADOField::PutPrecision(sal_Int8 _prec) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_Precision(_prec))); +} + +bool WpADOField::PutNumericScale(sal_Int8 _prec) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_NumericScale(_prec))); +} + +void WpADOField::PutADOType(DataTypeEnum eType) +{ + assert(pInterface); + pInterface->put_Type(eType); +} + +bool WpADOField::PutDefinedSize(sal_Int32 _nDefSize) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_DefinedSize(_nDefSize))); +} + +bool WpADOField::PutAttributes(sal_Int32 _nDefSize) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_Attributes(_nDefSize))); +} + +OLEVariant WpADOProperty::GetValue() const +{ + OLEVariant aValVar; + if(pInterface) + pInterface->get_Value(&aValVar); + return aValVar; +} + +void WpADOProperty::GetValue(OLEVariant &aValVar) const +{ + assert(pInterface); + if(pInterface) + pInterface->get_Value(&aValVar); +} + +bool WpADOProperty::PutValue(const OLEVariant &aValVar) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_Value(aValVar))); +} + +OUString WpADOProperty::GetName() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +DataTypeEnum WpADOProperty::GetADOType() const +{ + assert(pInterface); + DataTypeEnum eType=adEmpty; + pInterface->get_Type(&eType); + return eType; +} + +sal_Int32 WpADOProperty::GetAttributes() const +{ + assert(pInterface); + sal_Int32 eADOSFieldAttributes=0; + pInterface->get_Attributes(&eADOSFieldAttributes); + return eADOSFieldAttributes; +} + +bool WpADOProperty::PutAttributes(sal_Int32 _nDefSize) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_Attributes(_nDefSize))); +} + void WpADORecordset::Create() +{ + IClassFactory2* pInterface2 = nullptr; + HRESULT hr = CoGetClassObject( ADOS::CLSID_ADORECORDSET_21, + CLSCTX_INPROC_SERVER, + nullptr, + IID_IClassFactory2, + reinterpret_cast<void**>(&pInterface2) ); + + if( !FAILED( hr ) ) + { + ADORecordset *pRec = nullptr; + IUnknown *pOuter = nullptr; + hr = pInterface2->CreateInstanceLic( pOuter, + nullptr, + ADOS::IID_ADORECORDSET_21, + ADOS::GetKeyStr().asBSTR(), + reinterpret_cast<void**>(&pRec)); + + if( !FAILED( hr ) ) + { + operator=(pRec); + pRec->Release(); + } + + pInterface2->Release(); + } +} + +bool WpADORecordset::Open( + /* [optional][in] */ VARIANT Source, + /* [optional][in] */ VARIANT ActiveConnection, + /* [defaultvalue][in] */ CursorTypeEnum CursorType, + /* [defaultvalue][in] */ LockTypeEnum LockType, + /* [defaultvalue][in] */ sal_Int32 Options) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->Open(Source,ActiveConnection,CursorType,LockType,Options))); +} + + +LockTypeEnum WpADORecordset::GetLockType() +{ + assert(pInterface); + LockTypeEnum eType=adLockUnspecified; + pInterface->get_LockType(&eType); + return eType; +} + +void WpADORecordset::Close() +{ + assert(pInterface); + pInterface->Close(); +} + +bool WpADORecordset::Cancel() const +{ + assert(pInterface); + return (SUCCEEDED(pInterface->Cancel())); +} + +sal_Int32 WpADORecordset::get_State() +{ + assert(pInterface); + sal_Int32 nState = 0; + pInterface->get_State(&nState); + return nState; +} + +bool WpADORecordset::Supports( /* [in] */ CursorOptionEnum CursorOptions) +{ + assert(pInterface); + VARIANT_BOOL bSupports=VARIANT_FALSE; + pInterface->Supports(CursorOptions,&bSupports); + return bSupports == VARIANT_TRUE; +} + +PositionEnum_Param WpADORecordset::get_AbsolutePosition() +{ + assert(pInterface); + PositionEnum_Param aTemp=adPosUnknown; + pInterface->get_AbsolutePosition(&aTemp); + return aTemp; +} + +void WpADORecordset::GetDataSource(IUnknown** _pInterface) const +{ + assert(pInterface); + pInterface->get_DataSource(_pInterface); +} + +void WpADORecordset::PutRefDataSource(IUnknown* _pInterface) +{ + assert(pInterface); + pInterface->putref_DataSource(_pInterface); +} + +void WpADORecordset::GetBookmark(VARIANT& var) +{ + assert(pInterface); + pInterface->get_Bookmark(&var); +} + +OLEVariant WpADORecordset::GetBookmark() +{ + assert(pInterface); + OLEVariant var; + pInterface->get_Bookmark(&var); + return var; +} + +CompareEnum WpADORecordset::CompareBookmarks(const OLEVariant& left,const OLEVariant& right) +{ + assert(pInterface); + CompareEnum eNum=adCompareNotComparable; + pInterface->CompareBookmarks(left,right,&eNum); + return eNum; +} + +bool WpADORecordset::SetBookmark(const OLEVariant &pSafeAr) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_Bookmark(pSafeAr)); +} + + +WpADOFields WpADORecordset::GetFields() const +{ + assert(pInterface); + ADOFields* pFields=nullptr; + pInterface->get_Fields(&pFields); + WpADOFields aFields; + aFields.setWithOutAddRef(pFields); + return aFields; +} + + +bool WpADORecordset::Move(sal_Int32 nRows, VARIANT aBmk) {return pInterface && SUCCEEDED(pInterface->Move(nRows, aBmk));} +bool WpADORecordset::MoveNext() {return pInterface && SUCCEEDED(pInterface->MoveNext());} +bool WpADORecordset::MovePrevious() {return pInterface && SUCCEEDED(pInterface->MovePrevious());} +bool WpADORecordset::MoveFirst() {return pInterface && SUCCEEDED(pInterface->MoveFirst());} +bool WpADORecordset::MoveLast() {return pInterface && SUCCEEDED(pInterface->MoveLast());} + +bool WpADORecordset::IsAtBOF() const +{ + assert(pInterface); + VARIANT_BOOL bIsAtBOF=VARIANT_FALSE; + pInterface->get_BOF(&bIsAtBOF); + return bIsAtBOF == VARIANT_TRUE; +} + +bool WpADORecordset::IsAtEOF() const +{ + assert(pInterface); + VARIANT_BOOL bIsAtEOF=VARIANT_FALSE; + pInterface->get_EOF(&bIsAtEOF); + return bIsAtEOF == VARIANT_TRUE; +} + +bool WpADORecordset::Delete(AffectEnum eNum) +{ + assert(pInterface); + return SUCCEEDED(pInterface->Delete(eNum)); +} + +bool WpADORecordset::AddNew(const OLEVariant &FieldList,const OLEVariant &Values) +{ + assert(pInterface); + return SUCCEEDED(pInterface->AddNew(FieldList,Values)); +} + +bool WpADORecordset::Update(const OLEVariant &FieldList,const OLEVariant &Values) +{ + assert(pInterface); + return SUCCEEDED(pInterface->Update(FieldList,Values)); +} + +bool WpADORecordset::CancelUpdate() +{ + assert(pInterface); + return SUCCEEDED(pInterface->CancelUpdate()); +} + +WpADOProperties WpADORecordset::get_Properties() const +{ + assert(pInterface); + ADOProperties* pProps=nullptr; + pInterface->get_Properties(&pProps); + WpADOProperties aProps; + aProps.setWithOutAddRef(pProps); + return aProps; +} + +bool WpADORecordset::NextRecordset(OLEVariant& RecordsAffected,ADORecordset** ppiRset) +{ + assert(pInterface); + return SUCCEEDED(pInterface->NextRecordset(&RecordsAffected,ppiRset)); +} + +bool WpADORecordset::get_RecordCount(ADO_LONGPTR &_nRet) const +{ + assert(pInterface); + return SUCCEEDED(pInterface->get_RecordCount(&_nRet)); +} + +bool WpADORecordset::get_MaxRecords(ADO_LONGPTR &_nRet) const +{ + assert(pInterface); + return SUCCEEDED(pInterface->get_MaxRecords(&_nRet)); +} + +bool WpADORecordset::put_MaxRecords(ADO_LONGPTR _nRet) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_MaxRecords(_nRet)); +} + +bool WpADORecordset::get_CursorType(CursorTypeEnum &_nRet) const +{ + assert(pInterface); + return SUCCEEDED(pInterface->get_CursorType(&_nRet)); +} + +bool WpADORecordset::put_CursorType(CursorTypeEnum _nRet) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_CursorType(_nRet)); +} + +bool WpADORecordset::get_LockType(LockTypeEnum &_nRet) const +{ + assert(pInterface); + return SUCCEEDED(pInterface->get_LockType(&_nRet)); +} + +bool WpADORecordset::put_LockType(LockTypeEnum _nRet) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_LockType(_nRet)); +} + +bool WpADORecordset::get_CacheSize(sal_Int32 &_nRet) const +{ + assert(pInterface); + return SUCCEEDED(pInterface->get_CacheSize(&_nRet)); +} + +bool WpADORecordset::put_CacheSize(sal_Int32 _nRet) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_CacheSize(_nRet)); +} + +bool WpADORecordset::UpdateBatch(AffectEnum AffectRecords) +{ + assert(pInterface); + return SUCCEEDED(pInterface->UpdateBatch(AffectRecords)); +} + +OUString WpADOParameter::GetName() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +DataTypeEnum WpADOParameter::GetADOType() const +{ + assert(pInterface); + DataTypeEnum eType=adEmpty; + pInterface->get_Type(&eType); + return eType; +} + +void WpADOParameter::put_Type(const DataTypeEnum& _eType) +{ + assert(pInterface); + pInterface->put_Type(_eType); +} + +sal_Int32 WpADOParameter::GetAttributes() const +{ + assert(pInterface); + sal_Int32 eADOSFieldAttributes=0; + pInterface->get_Attributes(&eADOSFieldAttributes); + return eADOSFieldAttributes; +} + +sal_Int32 WpADOParameter::GetPrecision() const +{ + assert(pInterface); + sal_uInt8 eType=0; + pInterface->get_Precision(&eType); + return eType; +} + +sal_Int32 WpADOParameter::GetNumericScale() const +{ + assert(pInterface); + sal_uInt8 eType=0; + pInterface->get_NumericScale(&eType); + return eType; +} + +ParameterDirectionEnum WpADOParameter::get_Direction() const +{ + assert(pInterface); + ParameterDirectionEnum alParmDirection=adParamUnknown; + pInterface->get_Direction(&alParmDirection); + return alParmDirection; +} + +void WpADOParameter::GetValue(OLEVariant& aValVar) const +{ + assert(pInterface); + pInterface->get_Value(&aValVar); +} + +OLEVariant WpADOParameter::GetValue() const +{ + assert(pInterface); + OLEVariant aValVar; + pInterface->get_Value(&aValVar); + return aValVar; +} + +bool WpADOParameter::PutValue(const OLEVariant& aVariant) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_Value(aVariant))); +} +bool WpADOParameter::AppendChunk(const OLEVariant& aVariant) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->AppendChunk(aVariant))); +} +bool WpADOParameter::put_Size(sal_Int32 _nSize) +{ + assert(pInterface); + return (SUCCEEDED(pInterface->put_Size(_nSize))); +} + +OUString WpADOColumn::get_Name() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +OUString WpADOColumn::get_RelatedColumn() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_RelatedColumn(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void WpADOColumn::put_Name(const OUString& _rName) +{ + assert(pInterface); + OLEString bstr(_rName); + pInterface->put_Name(bstr.asBSTR()); +} +void WpADOColumn::put_RelatedColumn(const OUString& _rName) +{ + assert(pInterface); + OLEString bstr(_rName); + pInterface->put_RelatedColumn(bstr.asBSTR()); +} + +DataTypeEnum WpADOColumn::get_Type() const +{ + assert(pInterface); + DataTypeEnum eNum = adVarChar; + pInterface->get_Type(&eNum); + return eNum; +} + +void WpADOColumn::put_Type(const DataTypeEnum& _eNum) +{ + assert(pInterface); + pInterface->put_Type(_eNum); +} + +sal_Int32 WpADOColumn::get_Precision() const +{ + assert(pInterface); + sal_Int32 nPrec=0; + pInterface->get_Precision(&nPrec); + return nPrec; +} + +void WpADOColumn::put_Precision(sal_Int32 _nPre) +{ + assert(pInterface); + pInterface->put_Precision(_nPre); +} + +sal_Int32 WpADOColumn::get_DefinedSize() const +{ + assert(pInterface); + sal_Int32 nPrec=0; + pInterface->get_DefinedSize(&nPrec); + return nPrec; +} +sal_uInt8 WpADOColumn::get_NumericScale() const +{ + assert(pInterface); + sal_uInt8 nPrec=0; + pInterface->get_NumericScale(&nPrec); + return nPrec; +} + +void WpADOColumn::put_NumericScale(sal_Int8 _nScale) +{ + assert(pInterface); + pInterface->put_NumericScale(_nScale); +} + +SortOrderEnum WpADOColumn::get_SortOrder() const +{ + assert(pInterface); + SortOrderEnum nPrec=adSortAscending; + pInterface->get_SortOrder(&nPrec); + return nPrec; +} + +void WpADOColumn::put_SortOrder(SortOrderEnum _nScale) +{ + assert(pInterface); + pInterface->put_SortOrder(_nScale); +} + +ColumnAttributesEnum WpADOColumn::get_Attributes() const +{ + assert(pInterface); + ColumnAttributesEnum eNum=adColNullable; + pInterface->get_Attributes(&eNum); + return eNum; +} + +bool WpADOColumn::put_Attributes(const ColumnAttributesEnum& _eNum) +{ + assert(pInterface); + return SUCCEEDED(pInterface->put_Attributes(_eNum)); +} + +WpADOProperties WpADOColumn::get_Properties() const +{ + assert(pInterface); + ADOProperties* pProps = nullptr; + pInterface->get_Properties(&pProps); + WpADOProperties aProps; + + aProps.setWithOutAddRef(pProps); + return aProps; +} + +OUString WpADOKey::get_Name() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void WpADOKey::put_Name(const OUString& _rName) +{ + assert(pInterface); + OLEString bstr(_rName); + pInterface->put_Name(bstr.asBSTR()); +} + +KeyTypeEnum WpADOKey::get_Type() const +{ + assert(pInterface); + KeyTypeEnum eNum=adKeyPrimary; + pInterface->get_Type(&eNum); + return eNum; +} + +void WpADOKey::put_Type(const KeyTypeEnum& _eNum) +{ + assert(pInterface); + pInterface->put_Type(_eNum); +} + +OUString WpADOKey::get_RelatedTable() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_RelatedTable(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void WpADOKey::put_RelatedTable(const OUString& _rName) +{ + assert(pInterface); + OLEString bstr(_rName); + pInterface->put_RelatedTable(bstr.asBSTR()); +} + +RuleEnum WpADOKey::get_DeleteRule() const +{ + assert(pInterface); + RuleEnum eNum = adRINone; + pInterface->get_DeleteRule(&eNum); + return eNum; +} + +void WpADOKey::put_DeleteRule(const RuleEnum& _eNum) +{ + assert(pInterface); + pInterface->put_DeleteRule(_eNum); +} + +RuleEnum WpADOKey::get_UpdateRule() const +{ + assert(pInterface); + RuleEnum eNum = adRINone; + pInterface->get_UpdateRule(&eNum); + return eNum; +} + +void WpADOKey::put_UpdateRule(const RuleEnum& _eNum) +{ + assert(pInterface); + pInterface->put_UpdateRule(_eNum); +} + +WpADOColumns WpADOKey::get_Columns() const +{ + assert(pInterface); + ADOColumns* pCols = nullptr; + pInterface->get_Columns(&pCols); + WpADOColumns aCols; + aCols.setWithOutAddRef(pCols); + return aCols; +} + +OUString WpADOIndex::get_Name() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void WpADOIndex::put_Name(const OUString& _rName) +{ + assert(pInterface); + OLEString bstr(_rName); + pInterface->put_Name(bstr.asBSTR()); +} + +bool WpADOIndex::get_Clustered() const +{ + assert(pInterface); + VARIANT_BOOL eNum = VARIANT_FALSE; + pInterface->get_Clustered(&eNum); + return eNum == VARIANT_TRUE; +} + +void WpADOIndex::put_Clustered(bool _b) +{ + assert(pInterface); + pInterface->put_Clustered(_b ? VARIANT_TRUE : VARIANT_FALSE); +} + +bool WpADOIndex::get_Unique() const +{ + assert(pInterface); + VARIANT_BOOL eNum = VARIANT_FALSE; + pInterface->get_Unique(&eNum); + return eNum == VARIANT_TRUE; +} + +void WpADOIndex::put_Unique(bool _b) +{ + assert(pInterface); + pInterface->put_Unique(_b ? VARIANT_TRUE : VARIANT_FALSE); +} + +bool WpADOIndex::get_PrimaryKey() const +{ + assert(pInterface); + VARIANT_BOOL eNum = VARIANT_FALSE; + pInterface->get_PrimaryKey(&eNum); + return eNum == VARIANT_TRUE; +} + +void WpADOIndex::put_PrimaryKey(bool _b) +{ + assert(pInterface); + pInterface->put_PrimaryKey(_b ? VARIANT_TRUE : VARIANT_FALSE); +} + +WpADOColumns WpADOIndex::get_Columns() const +{ + assert(pInterface); + ADOColumns* pCols = nullptr; + pInterface->get_Columns(&pCols); + WpADOColumns aCols; + aCols.setWithOutAddRef(pCols); + return aCols; +} + +void WpADOCatalog::putref_ActiveConnection(IDispatch* pCon) +{ + assert(pInterface); + pInterface->putref_ActiveConnection(pCon); +} + +WpADOTables WpADOCatalog::get_Tables() +{ + assert(pInterface); + ADOTables* pRet = nullptr; + pInterface->get_Tables(&pRet); + WpADOTables aRet; + aRet.setWithOutAddRef(pRet); + return aRet; +} + +WpADOViews WpADOCatalog::get_Views() +{ + assert(pInterface); + ADOViews* pRet = nullptr; + pInterface->get_Views(&pRet); + WpADOViews aRet; + aRet.setWithOutAddRef(pRet); + return aRet; +} + +WpADOGroups WpADOCatalog::get_Groups() +{ + assert(pInterface); + ADOGroups* pRet = nullptr; + pInterface->get_Groups(&pRet); + WpADOGroups aRet; + aRet.setWithOutAddRef(pRet); + return aRet; +} + +WpADOUsers WpADOCatalog::get_Users() +{ + assert(pInterface); + ADOUsers* pRet = nullptr; + pInterface->get_Users(&pRet); + WpADOUsers aRet; + aRet.setWithOutAddRef(pRet); + return aRet; +} + +ADOProcedures* WpADOCatalog::get_Procedures() +{ + assert(pInterface); + ADOProcedures* pRet = nullptr; + pInterface->get_Procedures(&pRet); + return pRet; +} + +OUString WpADOTable::get_Name() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void WpADOTable::put_Name(const OUString& _rName) +{ + assert(pInterface); + OLEString bstr(_rName); + pInterface->put_Name(bstr.asBSTR()); +} + +OUString WpADOTable::get_Type() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Type(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +WpADOColumns WpADOTable::get_Columns() const +{ + assert(pInterface); + ADOColumns* pCols = nullptr; + pInterface->get_Columns(&pCols); + WpADOColumns aCols; + aCols.setWithOutAddRef(pCols); + return aCols; +} + +WpADOIndexes WpADOTable::get_Indexes() const +{ + assert(pInterface); + ADOIndexes* pCols = nullptr; + pInterface->get_Indexes(&pCols); + WpADOIndexes aRet; + aRet.setWithOutAddRef(pCols); + return aRet; +} + +WpADOKeys WpADOTable::get_Keys() const +{ + assert(pInterface); + ADOKeys* pCols = nullptr; + pInterface->get_Keys(&pCols); + WpADOKeys aRet; + aRet.setWithOutAddRef(pCols); + return aRet; +} + +WpADOCatalog WpADOTable::get_ParentCatalog() const +{ + assert(pInterface); + ADOCatalog* pCat = nullptr; + pInterface->get_ParentCatalog(&pCat); + WpADOCatalog aRet; + aRet.setWithOutAddRef(pCat); + return aRet; +} + +WpADOProperties WpADOTable::get_Properties() const +{ + assert(pInterface); + ADOProperties* pProps = nullptr; + pInterface->get_Properties(&pProps); + WpADOProperties aProps; + aProps.setWithOutAddRef(pProps); + return aProps; +} + +OUString WpADOView::get_Name() const +{ + assert(pInterface); + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void WpADOView::get_Command(OLEVariant& _rVar) const +{ + assert(pInterface); + pInterface->get_Command(&_rVar); +} + +void WpADOView::put_Command(OLEVariant const & _rVar) +{ + assert(pInterface); + pInterface->put_Command(_rVar); +} + +OUString WpADOGroup::get_Name() const +{ + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void WpADOGroup::put_Name(const OUString& _rName) +{ + OLEString bstr(_rName); + pInterface->put_Name(bstr.asBSTR()); +} + +RightsEnum WpADOGroup::GetPermissions( + /* [in] */ const OLEVariant& Name, + /* [in] */ ObjectTypeEnum ObjectType) +{ + RightsEnum Rights=adRightNone; + OLEVariant ObjectTypeId; + ObjectTypeId.setNoArg(); + pInterface->GetPermissions(Name,ObjectType,ObjectTypeId,&Rights); + return Rights; +} + +bool WpADOGroup::SetPermissions( + /* [in] */ const OLEVariant& Name, + /* [in] */ ObjectTypeEnum ObjectType, + /* [in] */ ActionEnum Action, + /* [in] */ RightsEnum Rights) +{ + OLEVariant ObjectTypeId; + ObjectTypeId.setNoArg(); + return SUCCEEDED(pInterface->SetPermissions(Name,ObjectType,Action,Rights,adInheritNone,ObjectTypeId)); +} + +WpADOUsers WpADOGroup::get_Users( ) +{ + ADOUsers* pRet = nullptr; + pInterface->get_Users( &pRet); + WpADOUsers aRet; + aRet.setWithOutAddRef(pRet); + return aRet; +} + +OUString WpADOUser::get_Name() const +{ + OLEString aBSTR; + pInterface->get_Name(aBSTR.getAddress()); + return aBSTR.asOUString(); +} + +void WpADOUser::put_Name(const OUString& _rName) +{ + OLEString bstr(_rName); + pInterface->put_Name(bstr.asBSTR()); +} + +bool WpADOUser::ChangePassword(const OUString& _rPwd,const OUString& _rNewPwd) +{ + OLEString sStr1(_rPwd); + OLEString sStr2(_rNewPwd); + bool bErg = SUCCEEDED(pInterface->ChangePassword(sStr1.asBSTR(),sStr2.asBSTR())); + return bErg; +} + +WpADOGroups WpADOUser::get_Groups() +{ + ADOGroups* pRet = nullptr; + pInterface->get_Groups(&pRet); + WpADOGroups aRet; + aRet.setWithOutAddRef(pRet); + return aRet; +} + +RightsEnum WpADOUser::GetPermissions( + /* [in] */ const OLEVariant& Name, + /* [in] */ ObjectTypeEnum ObjectType) +{ + RightsEnum Rights=adRightNone; + OLEVariant ObjectTypeId; + ObjectTypeId.setNoArg(); + pInterface->GetPermissions(Name,ObjectType,ObjectTypeId,&Rights); + return Rights; +} + +bool WpADOUser::SetPermissions( + /* [in] */ const OLEVariant& Name, + /* [in] */ ObjectTypeEnum ObjectType, + /* [in] */ ActionEnum Action, + /* [in] */ RightsEnum Rights) +{ + OLEVariant ObjectTypeId; + ObjectTypeId.setNoArg(); + return SUCCEEDED(pInterface->SetPermissions(Name,ObjectType,Action,Rights,adInheritNone,ObjectTypeId)); +} + +WpBase::WpBase() : pIUnknown(nullptr) +{ +} +WpBase::WpBase(IDispatch* pInt) + :pIUnknown(pInt) +{ + if (pIUnknown) + { + pIUnknown->AddRef(); + } +} + +WpBase::WpBase(const WpBase& aWrapper) + :pIUnknown(aWrapper.pIUnknown) +{ + if (pIUnknown) + pIUnknown->AddRef(); +} + +//inline +WpBase& WpBase::operator=(const WpBase& rhs) +{ + operator=(rhs.pIUnknown); + return *this; +}; + +WpBase& WpBase::operator=(IDispatch* rhs) +{ + if (pIUnknown != rhs) + { + if (pIUnknown) + pIUnknown->Release(); + pIUnknown = rhs; + if (pIUnknown) + pIUnknown->AddRef(); + } + return *this; +} + +WpBase::~WpBase() +{ + if (pIUnknown) + { + pIUnknown->Release(); + pIUnknown = nullptr; + } +} + +void WpBase::clear() +{ + if (pIUnknown) + { + pIUnknown->Release(); + pIUnknown = nullptr; + } +} + + +bool WpBase::IsValid() const +{ + return pIUnknown != nullptr; +} +WpBase::operator IDispatch*() +{ + return pIUnknown; +} + +ADORecordset* WpADOConnection::getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) +{ + // Create elements used in the array + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[6]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schema.getLength() && schema.toChar() != '%') + varCriteria[nPos].setString(schema); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + varCriteria[nPos].setString(table); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaForeignKeys,vsa,vtEmpty,&pRecordset); + return pRecordset; +} + +ADORecordset* WpADOConnection::getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) +{ + // Create elements used in the array + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[6]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schema.getLength() && schema.toChar() != '%') + varCriteria[nPos].setString(schema); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + varCriteria[nPos].setString(table); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaForeignKeys,vsa,vtEmpty,&pRecordset); + + return pRecordset; + +} + +ADORecordset* WpADOConnection::getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) +{ + // Create elements used in the array + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[3]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schema.getLength() && schema.toChar() != '%') + varCriteria[nPos].setString(schema); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + varCriteria[nPos].setString(table); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaPrimaryKeys,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getIndexInfo( + const css::uno::Any& catalog, const OUString& schema, const OUString& table, + bool /*unique*/, bool /*approximate*/ ) +{ + // Create elements used in the array + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[5]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schema.getLength() && schema.toChar() != '%') + varCriteria[nPos].setString(schema); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// INDEX_NAME + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TYPE + + varCriteria[nPos].setString(table); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaIndexes,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getTablePrivileges( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& tableNamePattern ) +{ + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[5]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schemaPattern.getLength() && schemaPattern.toChar() != '%') + varCriteria[nPos].setString(schemaPattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + if(tableNamePattern.toChar() != '%') + varCriteria[nPos].setString(tableNamePattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// GRANTOR + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// GRANTEE + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaTablePrivileges,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getCrossReference( const css::uno::Any& primaryCatalog, + const OUString& primarySchema, + const OUString& primaryTable, + const css::uno::Any& foreignCatalog, + const OUString& foreignSchema, + const OUString& foreignTable) +{ + // Create elements used in the array + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[6]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(primaryCatalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(primaryCatalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(primarySchema.getLength() && primarySchema.toChar() != '%') + varCriteria[nPos].setString(primarySchema); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + varCriteria[nPos].setString(primaryTable); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + if(foreignCatalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(foreignCatalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(foreignSchema.getLength() && foreignSchema.toChar() != '%') + varCriteria[nPos].setString(foreignSchema); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + varCriteria[nPos].setString(foreignTable); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaForeignKeys,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getProcedures( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& procedureNamePattern ) +{ + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[3]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schemaPattern.getLength() && schemaPattern.toChar() != '%') + varCriteria[nPos].setString(schemaPattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + if(procedureNamePattern.toChar() != '%') + varCriteria[nPos].setString(procedureNamePattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaProcedures,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getProcedureColumns( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& procedureNamePattern, + const OUString& columnNamePattern ) +{ + // Create elements used in the array + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[4]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schemaPattern.getLength() && schemaPattern.toChar() != '%') + varCriteria[nPos].setString(schemaPattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + if(procedureNamePattern.toChar() != '%') + varCriteria[nPos].setString(procedureNamePattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + if(columnNamePattern.toChar() != '%') + varCriteria[nPos].setString(columnNamePattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// COLUMN_NAME + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaProcedureParameters,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getTables( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence< OUString >& types ) +{ + // Create elements used in the array + HRESULT hr = S_OK; + OLEVariant varCriteria[4]; + + sal_Int32 nPos=0; + OUString sCatalog; + if ( catalog.hasValue() && (catalog >>= sCatalog) ) + varCriteria[nPos].setString(sCatalog); + + ++nPos; + if(schemaPattern.getLength() && schemaPattern.toChar() != '%') + varCriteria[nPos].setString(schemaPattern); + + ++nPos; + if(tableNamePattern.toChar() != '%') + varCriteria[nPos].setString(tableNamePattern); + + ++nPos; + OUStringBuffer aTypes; + const OUString* pIter = types.getConstArray(); + const OUString* pEnd = pIter + types.getLength(); + for( ; pIter != pEnd ; ++pIter) + { + if ( aTypes.getLength() ) + aTypes.append(","); + aTypes.append(*pIter); + } + + OUString sTypeNames = aTypes.makeStringAndClear(); + if ( sTypeNames.getLength() ) + varCriteria[nPos].setString(sTypeNames); + + // Create SafeArray Bounds and initialize the array + const sal_Int32 nCrit = SAL_N_ELEMENTS(varCriteria); + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = nCrit; + SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + // Set the values for each element of the array + for( long i = 0 ; i < nCrit && SUCCEEDED( hr );i++) + { + hr = SafeArrayPutElement(psa, &i,&varCriteria[i]); + } + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaTables,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getColumns( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + // Create elements used in the array + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[4]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schemaPattern.getLength() && schemaPattern.toChar() != '%') + varCriteria[nPos].setString(schemaPattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + if(tableNamePattern.toChar() != '%') + varCriteria[nPos].setString(tableNamePattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + varCriteria[nPos].setString(columnNamePattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// COLUMN_NAME + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaColumns,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getColumnPrivileges( const css::uno::Any& catalog, + const OUString& schema, + const OUString& table, + const OUString& columnNamePattern ) +{ + // Create elements used in the array + SAFEARRAYBOUND rgsabound[1]; + SAFEARRAY *psa = nullptr; + OLEVariant varCriteria[4]; + + // Create SafeArray Bounds and initialize the array + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = SAL_N_ELEMENTS(varCriteria); + psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos=0; + if(catalog.hasValue()) + varCriteria[nPos].setString(::comphelper::getString(catalog)); + + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_CATALOG + if(schema.getLength() && schema.toChar() != '%') + varCriteria[nPos].setString(schema); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_SCHEMA + + varCriteria[nPos].setString(table); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// TABLE_NAME + + varCriteria[nPos].setString(columnNamePattern); + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++;// COLUMN_NAME + + OLEVariant vtEmpty; + vtEmpty.setNoArg(); + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + ADORecordset *pRecordset = nullptr; + OpenSchema(adSchemaColumnPrivileges,vsa,vtEmpty,&pRecordset); + + return pRecordset; +} + +ADORecordset* WpADOConnection::getTypeInfo(DataTypeEnum /*_eType*/) +{ + // Create elements used in the array + OLEVariant varCriteria[2]; + const int nCrit = SAL_N_ELEMENTS(varCriteria); + // Create SafeArray Bounds and initialize the array + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = nCrit; + SAFEARRAY *psa = SafeArrayCreate( VT_VARIANT, 1, rgsabound ); + + sal_Int32 nPos = 0; + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++; + SafeArrayPutElement(psa,&nPos,&varCriteria[nPos]);nPos++; + + // Initialize and fill the SafeArray + OLEVariant vsa; + vsa.setArray(psa,VT_VARIANT); + + OLEVariant aEmpty; + aEmpty.setNoArg(); + + ADORecordset *pRec=nullptr; + OpenSchema(adSchemaProviderTypes,vsa,aEmpty,&pRec); + + return pRec; +} + +void WpADOColumn::put_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject) +{ + assert(pInterface); + bool bRet = SUCCEEDED(pInterface->put_ParentCatalog(ppvObject)); + SAL_WARN_IF(!bRet, "connectivity.ado", "Could not set ParentCatalog!"); +} + +void WpADOTable::putref_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject) +{ + assert(pInterface); + bool bRet = SUCCEEDED(pInterface->putref_ParentCatalog(ppvObject)); + SAL_WARN_IF(!bRet, "connectivity.ado", "Could not set ParentCatalog!"); +} + +void WpBase::setIDispatch(IDispatch* _pIUnknown) +{ + pIUnknown = _pIUnknown; +} + +void OTools::putValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition,const OLEVariant &_aValVar) +{ + SAL_WARN_IF(!_rProps.IsValid(), "connectivity.ado", "Properties are not valid!"); + WpADOProperty aProp(_rProps.GetItem(_aPosition)); + if ( aProp.IsValid() ) + { + bool bRet = aProp.PutValue(_aValVar); + SAL_WARN_IF(!bRet, "connectivity.ado", "Could not put value!"); + } +} + +OLEVariant OTools::getValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition) +{ + WpADOProperty aProp(_rProps.GetItem(_aPosition)); + return aProp.GetValue(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/ado/ado.component b/connectivity/source/drivers/ado/ado.component new file mode 100644 index 000000000..b90673ae8 --- /dev/null +++ b/connectivity/source/drivers/ado/ado.component @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" + environment="@CPPU_ENV@:affine" prefix="ado" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.ado.ODriver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/ado/adoimp.cxx b/connectivity/source/drivers/ado/adoimp.cxx new file mode 100644 index 000000000..1e368d8dd --- /dev/null +++ b/connectivity/source/drivers/ado/adoimp.cxx @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/PrivilegeObject.hpp> +#include <connectivity/dbexception.hxx> +#include <ado/Awrapado.hxx> +#include <ado/adoimp.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/sdbc/DataType.hpp> + + +using namespace connectivity::ado; +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; + + +#define MYADOID(l) {l, 0,0x10,{0x80,0,0,0xAA,0,0x6D,0x2E,0xA4}}; + +const CLSID ADOS::CLSID_ADOCONNECTION_21 = MYADOID(0x00000514); +const IID ADOS::IID_ADOCONNECTION_21 = MYADOID(0x00000550); + +const CLSID ADOS::CLSID_ADOCOMMAND_21 = MYADOID(0x00000507); +const IID ADOS::IID_ADOCOMMAND_21 = MYADOID(0x0000054E); + +const CLSID ADOS::CLSID_ADORECORDSET_21 = MYADOID(0x00000535); +const IID ADOS::IID_ADORECORDSET_21 = MYADOID(0x0000054F); + +const CLSID ADOS::CLSID_ADOCATALOG_25 = MYADOID(0x00000602); +const IID ADOS::IID_ADOCATALOG_25 = MYADOID(0x00000603); + +const CLSID ADOS::CLSID_ADOINDEX_25 = MYADOID(0x0000061E); +const IID ADOS::IID_ADOINDEX_25 = MYADOID(0x0000061F); + +const CLSID ADOS::CLSID_ADOTABLE_25 = MYADOID(0x00000609); +const IID ADOS::IID_ADOTABLE_25 = MYADOID(0x00000610); + +const CLSID ADOS::CLSID_ADOKEY_25 = MYADOID(0x00000621); +const IID ADOS::IID_ADOKEY_25 = MYADOID(0x00000622); + +const CLSID ADOS::CLSID_ADOCOLUMN_25 = MYADOID(0x0000061B); +const IID ADOS::IID_ADOCOLUMN_25 = MYADOID(0x0000061C); + +const CLSID ADOS::CLSID_ADOGROUP_25 = MYADOID(0x00000615); +const IID ADOS::IID_ADOGROUP_25 = MYADOID(0x00000616); + +const CLSID ADOS::CLSID_ADOUSER_25 = MYADOID(0x00000618); +const IID ADOS::IID_ADOUSER_25 = MYADOID(0x00000619); + +const CLSID ADOS::CLSID_ADOVIEW_25 = MYADOID(0x00000612); +const IID ADOS::IID_ADOVIEW_25 = MYADOID(0x00000613); + +OLEString& ADOS::GetKeyStr() +{ + static OLEString sKeyStr(OUString("gxwaezucfyqpwjgqbcmtsncuhwsnyhiohwxz")); + return sKeyStr; +} + + +sal_Int32 ADOS::MapADOType2Jdbc(DataTypeEnum eType) +{ + sal_Int32 nType = DataType::VARCHAR; + switch (eType) + { + case adUnsignedSmallInt: + case adSmallInt: nType = DataType::SMALLINT; break; + case adUnsignedInt: + case adInteger: nType = DataType::INTEGER; break; + case adUnsignedBigInt: + case adBigInt: nType = DataType::BIGINT; break; + case adSingle: nType = DataType::FLOAT; break; + case adDouble: nType = DataType::DOUBLE; break; + case adCurrency: nType = DataType::DOUBLE; break; + case adVarNumeric: + case adNumeric: nType = DataType::NUMERIC; break; + case adDecimal: nType = DataType::DECIMAL; break; + case adDBDate: nType = DataType::DATE; break; + case adDBTime: nType = DataType::TIME; break; + case adDate: + case adDBTimeStamp: nType = DataType::TIMESTAMP; break; + case adBoolean: nType = DataType::BOOLEAN; break; +// case adArray: nType = DataType::ARRAY; break; + case adBinary: nType = DataType::BINARY; break; + case adGUID: nType = DataType::OBJECT; break; + case adBSTR: + case adVarWChar: + case adWChar: + case adVarChar: nType = DataType::VARCHAR; break; + case adLongVarWChar: + case adLongVarChar: nType = DataType::LONGVARCHAR; break; + case adVarBinary: nType = DataType::VARBINARY; break; + case adLongVarBinary: nType = DataType::LONGVARBINARY;break; + case adChar: nType = DataType::CHAR; break; + case adUnsignedTinyInt: + case adTinyInt: nType = DataType::TINYINT; break; + case adEmpty: nType = DataType::SQLNULL; break; + case adUserDefined: + case adPropVariant: + case adFileTime: + case adChapter: + case adIDispatch: + case adIUnknown: + case adError: + case adVariant: + nType = DataType::OTHER; break; + default: + OSL_FAIL("MapADOType2Jdbc: Unknown Type!"); + ; + } + return nType; +} + +DataTypeEnum ADOS::MapJdbc2ADOType(sal_Int32 _nType,sal_Int32 _nJetEngine) +{ + switch (_nType) + { + case DataType::SMALLINT: return adSmallInt; break; + case DataType::INTEGER: return adInteger; break; + case DataType::BIGINT: return adBigInt; break; + case DataType::FLOAT: return adSingle; break; + case DataType::DOUBLE: return adDouble; break; + case DataType::NUMERIC: return adNumeric; break; + case DataType::DECIMAL: return adDecimal; break; + case DataType::DATE: return isJetEngine(_nJetEngine) ? adDate : adDBDate; break; + case DataType::TIME: return adDBTime; break; + case DataType::TIMESTAMP: return isJetEngine(_nJetEngine) ? adDate : adDBTimeStamp; break; + case DataType::BOOLEAN: + case DataType::BIT: return adBoolean; break; + case DataType::BINARY: return adBinary; break; + case DataType::VARCHAR: return adVarWChar; break; + case DataType::CLOB: + case DataType::LONGVARCHAR: return adLongVarWChar; break; + case DataType::VARBINARY: return adVarBinary; break; + case DataType::BLOB: + case DataType::LONGVARBINARY: return adLongVarBinary; break; + case DataType::CHAR: return adWChar; break; + case DataType::TINYINT: return isJetEngine(_nJetEngine) ? adUnsignedTinyInt : adTinyInt;break; + case DataType::OBJECT: return adGUID; break; + default: + OSL_FAIL("MapJdbc2ADOType: Unknown Type!"); + ; + } + return adEmpty; +} + +const int JET_ENGINETYPE_UNKNOWN = 0; +const int JET_ENGINETYPE_JET10 = 1; +const int JET_ENGINETYPE_JET11 = 2; +const int JET_ENGINETYPE_JET20 = 3; +const int JET_ENGINETYPE_JET3X = 4; +const int JET_ENGINETYPE_JET4X = 5; +const int JET_ENGINETYPE_DBASE3 = 10; +const int JET_ENGINETYPE_DBASE4 = 11; +const int JET_ENGINETYPE_DBASE5 = 12; +const int JET_ENGINETYPE_EXCEL30 = 20; +const int JET_ENGINETYPE_EXCEL40 = 21; +const int JET_ENGINETYPE_EXCEL50 = 22; +const int JET_ENGINETYPE_EXCEL80 = 23; +const int JET_ENGINETYPE_EXCEL90 = 24; +const int JET_ENGINETYPE_EXCHANGE4 = 30; +const int JET_ENGINETYPE_LOTUSWK1 = 40; +const int JET_ENGINETYPE_LOTUSWK3 = 41; +const int JET_ENGINETYPE_LOTUSWK4 = 42; +const int JET_ENGINETYPE_PARADOX3X = 50; +const int JET_ENGINETYPE_PARADOX4X = 51; +const int JET_ENGINETYPE_PARADOX5X = 52; +const int JET_ENGINETYPE_PARADOX7X = 53; +const int JET_ENGINETYPE_TEXT1X = 60; +const int JET_ENGINETYPE_HTML1X = 70; + +bool ADOS::isJetEngine(sal_Int32 _nEngineType) +{ + bool bRet = false; + switch(_nEngineType) + { + case JET_ENGINETYPE_UNKNOWN: + case JET_ENGINETYPE_JET10: + case JET_ENGINETYPE_JET11: + case JET_ENGINETYPE_JET20: + case JET_ENGINETYPE_JET3X: + case JET_ENGINETYPE_JET4X: + case JET_ENGINETYPE_DBASE3: + case JET_ENGINETYPE_DBASE4: + case JET_ENGINETYPE_DBASE5: + case JET_ENGINETYPE_EXCEL30: + case JET_ENGINETYPE_EXCEL40: + case JET_ENGINETYPE_EXCEL50: + case JET_ENGINETYPE_EXCEL80: + case JET_ENGINETYPE_EXCEL90: + case JET_ENGINETYPE_EXCHANGE4: + case JET_ENGINETYPE_LOTUSWK1: + case JET_ENGINETYPE_LOTUSWK3: + case JET_ENGINETYPE_LOTUSWK4: + case JET_ENGINETYPE_PARADOX3X: + case JET_ENGINETYPE_PARADOX4X: + case JET_ENGINETYPE_PARADOX5X: + case JET_ENGINETYPE_PARADOX7X: + case JET_ENGINETYPE_TEXT1X: + case JET_ENGINETYPE_HTML1X: + bRet = true; + break; + } + return bRet; +} + +ObjectTypeEnum ADOS::mapObjectType2Ado(sal_Int32 objType) +{ + ObjectTypeEnum eType = adPermObjTable; + switch(objType) + { + case PrivilegeObject::TABLE: + eType = adPermObjTable; + break; + case PrivilegeObject::VIEW: + eType = adPermObjView; + break; + case PrivilegeObject::COLUMN: + eType = adPermObjColumn; + break; + } + return eType; +} + +sal_Int32 ADOS::mapAdoType2Object(ObjectTypeEnum objType) +{ + sal_Int32 nType = PrivilegeObject::TABLE; + switch(objType) + { + case adPermObjTable: + nType = PrivilegeObject::TABLE; + break; + case adPermObjView: + nType = PrivilegeObject::VIEW; + break; + case adPermObjColumn: + nType = PrivilegeObject::COLUMN; + break; + default: + OSL_FAIL( "ADOS::mapAdoType2Object: privilege type cannot be translated!" ); + break; + } + return nType; +} +#ifdef DELETE +#undef DELETE +#endif + +sal_Int32 ADOS::mapAdoRights2Sdbc(RightsEnum eRights) +{ + sal_Int32 nRights = 0; + if((eRights & adRightInsert) == adRightInsert) + nRights |= Privilege::INSERT; + if((eRights & adRightDelete) == adRightDelete) + nRights |= css::sdbcx::Privilege::DELETE; + if((eRights & adRightUpdate) == adRightUpdate) + nRights |= Privilege::UPDATE; + if((eRights & adRightWriteDesign) == adRightWriteDesign) + nRights |= Privilege::ALTER; + if((eRights & adRightRead) == adRightRead) + nRights |= Privilege::SELECT; + if((eRights & adRightReference) == adRightReference) + nRights |= Privilege::REFERENCE; + if((eRights & adRightDrop) == adRightDrop) + nRights |= Privilege::DROP; + + return nRights; +} + +sal_Int32 ADOS::mapRights2Ado(sal_Int32 nRights) +{ + sal_Int32 eRights = adRightNone; + + if((nRights & Privilege::INSERT) == Privilege::INSERT) + eRights |= adRightInsert; + if((nRights & Privilege::DELETE) == Privilege::DELETE) + eRights |= adRightDelete; + if((nRights & Privilege::UPDATE) == Privilege::UPDATE) + eRights |= adRightUpdate; + if((nRights & Privilege::ALTER) == Privilege::ALTER) + eRights |= adRightWriteDesign; + if((nRights & Privilege::SELECT) == Privilege::SELECT) + eRights |= adRightRead; + if((nRights & Privilege::REFERENCE) == Privilege::REFERENCE) + eRights |= adRightReference; + if((nRights & Privilege::DROP) == Privilege::DROP) + eRights |= adRightDrop; + + return eRights; +} + +WpADOField ADOS::getField(ADORecordset* _pRecordSet,sal_Int32 _nColumnIndex) +{ + if ( !_pRecordSet ) + return WpADOField(); + + ADOFields* pFields = nullptr; + _pRecordSet->get_Fields(&pFields); + WpOLEAppendCollection<ADOFields, ADOField, WpADOField> aFields(pFields); + if(_nColumnIndex <= 0 || _nColumnIndex > aFields.GetItemCount()) + ::dbtools::throwInvalidIndexException(nullptr); + WpADOField aField(aFields.GetItem(_nColumnIndex-1)); + if(!aField.IsValid()) + ::dbtools::throwInvalidIndexException(nullptr); + return aField; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/calc/CCatalog.cxx b/connectivity/source/drivers/calc/CCatalog.cxx new file mode 100644 index 000000000..6853a5f9d --- /dev/null +++ b/connectivity/source/drivers/calc/CCatalog.cxx @@ -0,0 +1,64 @@ +/* -*- 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 <calc/CCatalog.hxx> +#include <calc/CConnection.hxx> +#include <calc/CTables.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> + +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 connectivity::calc; + +OCalcCatalog::OCalcCatalog(OCalcConnection* _pCon) : file::OFileCatalog(_pCon) +{ +} + +void OCalcCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + Sequence< OUString > aTypes; + OCalcConnection::ODocHolder aDocHolder(static_cast<OCalcConnection*>(m_pConnection)); + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), + "%", "%", aTypes); + + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while(xResult->next()) + aVector.push_back(xRow->getString(3)); + } + if(m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset( new OCalcTables(m_xMetaData,*this,m_aMutex,aVector) ); + + // this avoids that the document will be loaded a 2nd time when one table will be accessed. + //if ( m_pTables && m_pTables->hasElements() ) + // m_pTables->getByIndex(0); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/calc/CConnection.cxx b/connectivity/source/drivers/calc/CConnection.cxx new file mode 100644 index 000000000..9b03d473b --- /dev/null +++ b/connectivity/source/drivers/calc/CConnection.cxx @@ -0,0 +1,268 @@ +/* -*- 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 <calc/CConnection.hxx> +#include <calc/CDatabaseMetaData.hxx> +#include <calc/CCatalog.hxx> +#include <calc/CDriver.hxx> +#include <resource/sharedresources.hxx> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <tools/urlobj.hxx> +#include <component/CPreparedStatement.hxx> +#include <component/CStatement.hxx> +#include <unotools/pathoptions.hxx> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <strings.hrc> + +using namespace connectivity::calc; +using namespace connectivity::file; + +typedef connectivity::file::OConnection OConnection_BASE; + + +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::lang; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::sheet; + + +OCalcConnection::OCalcConnection(ODriver* _pDriver) : OConnection(_pDriver),m_nDocCount(0) +{ + // m_aFilenameExtension is not used +} + +OCalcConnection::~OCalcConnection() +{ +} + +void OCalcConnection::construct(const OUString& url,const Sequence< PropertyValue >& info) +{ + // open file + + sal_Int32 nLen = url.indexOf(':'); + nLen = url.indexOf(':',nLen+1); + OUString aDSN(url.copy(nLen+1)); + + m_aFileName = aDSN; + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + { + SvtPathOptions aPathOptions; + m_aFileName = aPathOptions.SubstituteVariable(m_aFileName); + } + aURL.SetSmartURL(m_aFileName); + if ( aURL.GetProtocol() == INetProtocol::NotValid ) + { + // don't pass invalid URL to loadComponentFromURL + throw SQLException(); + } + m_aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + + m_sPassword.clear(); + const char pPwd[] = "password"; + + const PropertyValue *pIter = info.getConstArray(); + const PropertyValue *pEnd = pIter + info.getLength(); + for(;pIter != pEnd;++pIter) + { + if(pIter->Name == pPwd) + { + pIter->Value >>= m_sPassword; + break; + } + } // for(;pIter != pEnd;++pIter) + ODocHolder aDocHolder(this); // just to test that the doc can be loaded + acquireDoc(); +} + +Reference< XSpreadsheetDocument> const & OCalcConnection::acquireDoc() +{ + if ( m_xDoc.is() ) + { + osl_atomic_increment(&m_nDocCount); + return m_xDoc; + } + // open read-only as long as updating isn't implemented + Sequence<PropertyValue> aArgs(2); + aArgs[0].Name = "Hidden"; + aArgs[0].Value <<= true; + aArgs[1].Name = "ReadOnly"; + aArgs[1].Value <<= true; + + if ( !m_sPassword.isEmpty() ) + { + const sal_Int32 nPos = aArgs.getLength(); + aArgs.realloc(nPos+1); + aArgs[nPos].Name = "Password"; + aArgs[nPos].Value <<= m_sPassword; + } + + Reference< XDesktop2 > xDesktop = Desktop::create( getDriver()->getComponentContext() ); + Reference< XComponent > xComponent; + Any aLoaderException; + try + { + xComponent = xDesktop->loadComponentFromURL( + m_aFileName, "_blank", 0, aArgs ); + } + catch( const Exception& ) + { + aLoaderException = ::cppu::getCaughtException(); + } + + m_xDoc.set(xComponent, UNO_QUERY ); + + // if the URL is not a spreadsheet document, throw the exception here + // instead of at the first access to it + if ( !m_xDoc.is() ) + { + Any aErrorDetails; + if ( aLoaderException.hasValue() ) + { + Exception aLoaderError; + OSL_VERIFY( aLoaderException >>= aLoaderError ); + + SQLException aDetailException; + aDetailException.Message = m_aResources.getResourceStringWithSubstitution( + STR_LOAD_FILE_ERROR_MESSAGE, + "$exception_type$", aLoaderException.getValueTypeName(), + "$error_message$", aLoaderError.Message + ); + aErrorDetails <<= aDetailException; + } + + const OUString sError( m_aResources.getResourceStringWithSubstitution( + STR_COULD_NOT_LOAD_FILE, + "$filename$", m_aFileName + ) ); + ::dbtools::throwGenericSQLException( sError, *this, aErrorDetails ); + } + osl_atomic_increment(&m_nDocCount); + m_xCloseVetoButTerminateListener.set(new CloseVetoButTerminateListener); + m_xCloseVetoButTerminateListener->start(m_xDoc, xDesktop); + return m_xDoc; +} + +void OCalcConnection::releaseDoc() +{ + if ( osl_atomic_decrement(&m_nDocCount) == 0 ) + { + if (m_xCloseVetoButTerminateListener.is()) + { + m_xCloseVetoButTerminateListener->stop(); // dispose m_xDoc + m_xCloseVetoButTerminateListener.clear(); + } + m_xDoc.clear(); + } +} + +void OCalcConnection::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + m_nDocCount = 0; + if (m_xCloseVetoButTerminateListener.is()) + { + m_xCloseVetoButTerminateListener->stop(); // dispose m_xDoc + m_xCloseVetoButTerminateListener.clear(); + } + m_xDoc.clear(); + + OConnection::disposing(); +} + +// XServiceInfo + + +IMPLEMENT_SERVICE_INFO(OCalcConnection, "com.sun.star.sdbc.drivers.calc.Connection", "com.sun.star.sdbc.Connection") + + +Reference< XDatabaseMetaData > SAL_CALL OCalcConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new OCalcDatabaseMetaData(this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + + +css::uno::Reference< XTablesSupplier > OCalcConnection::createCatalog() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XTablesSupplier > xTab = m_xCatalog; + if(!xTab.is()) + { + OCalcCatalog *pCat = new OCalcCatalog(this); + xTab = pCat; + m_xCatalog = xTab; + } + return xTab; +} + + +Reference< XStatement > SAL_CALL OCalcConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + Reference< XStatement > xReturn = new connectivity::component::OComponentStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + + +Reference< XPreparedStatement > SAL_CALL OCalcConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + auto pStmt = new connectivity::component::OComponentPreparedStatement(this); + Reference< XPreparedStatement > xHoldAlive = pStmt; + pStmt->construct(sql); + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return pStmt; +} + + +Reference< XPreparedStatement > SAL_CALL OCalcConnection::prepareCall( const OUString& /*sql*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this ); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/calc/CDatabaseMetaData.cxx b/connectivity/source/drivers/calc/CDatabaseMetaData.cxx new file mode 100644 index 000000000..cea1b32c7 --- /dev/null +++ b/connectivity/source/drivers/calc/CDatabaseMetaData.cxx @@ -0,0 +1,220 @@ +/* -*- 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 <calc/CDatabaseMetaData.hxx> +#include <calc/CConnection.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XDatabaseRanges.hpp> +#include <com/sun/star/sheet/XDatabaseRange.hpp> +#include <FDatabaseMetaDataResultSet.hxx> + +using namespace connectivity::calc; +using namespace connectivity::file; +using namespace connectivity::component; +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::table; +using namespace ::com::sun::star::sheet; + +OCalcDatabaseMetaData::OCalcDatabaseMetaData(OConnection* _pCon) :OComponentDatabaseMetaData(_pCon) +{ +} + +OCalcDatabaseMetaData::~OCalcDatabaseMetaData() +{ +} + +OUString SAL_CALL OCalcDatabaseMetaData::getURL( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return "sdbc:calc:" + m_pConnection->getURL(); +} + +static bool lcl_IsEmptyOrHidden( const Reference<XSpreadsheets>& xSheets, const OUString& rName ) +{ + Any aAny = xSheets->getByName( rName ); + Reference<XSpreadsheet> xSheet; + if ( aAny >>= xSheet ) + { + // test if sheet is hidden + + Reference<XPropertySet> xProp( xSheet, UNO_QUERY ); + if (xProp.is()) + { + bool bVisible; + Any aVisAny = xProp->getPropertyValue("IsVisible"); + if ( (aVisAny >>= bVisible) && !bVisible) + return true; // hidden + } + + // use the same data area as in OCalcTable to test for empty table + + Reference<XSheetCellCursor> xCursor = xSheet->createCursor(); + Reference<XCellRangeAddressable> xRange( xCursor, UNO_QUERY ); + if ( xRange.is() ) + { + xCursor->collapseToSize( 1, 1 ); // single (first) cell + xCursor->collapseToCurrentRegion(); // contiguous data area + + CellRangeAddress aRangeAddr = xRange->getRangeAddress(); + if ( aRangeAddr.StartColumn == aRangeAddr.EndColumn && + aRangeAddr.StartRow == aRangeAddr.EndRow ) + { + // single cell -> check content + Reference<XCell> xCell = xCursor->getCellByPosition( 0, 0 ); + if ( xCell.is() && xCell->getType() == CellContentType_EMPTY ) + return true; + } + } + } + + return false; +} + +static bool lcl_IsUnnamed( const Reference<XDatabaseRanges>& xRanges, const OUString& rName ) +{ + bool bUnnamed = false; + + Any aAny = xRanges->getByName( rName ); + Reference<XDatabaseRange> xRange; + if ( aAny >>= xRange ) + { + Reference<XPropertySet> xRangeProp( xRange, UNO_QUERY ); + if ( xRangeProp.is() ) + { + try + { + Any aUserAny = xRangeProp->getPropertyValue("IsUserDefined"); + bool bUserDefined; + if ( aUserAny >>= bUserDefined ) + bUnnamed = !bUserDefined; + } + catch ( UnknownPropertyException& ) + { + // optional property + } + } + } + + return bUnnamed; +} + +Reference< XResultSet > SAL_CALL OCalcDatabaseMetaData::getTables( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, + const OUString& tableNamePattern, const Sequence< OUString >& types ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables); + Reference< XResultSet > xRef = pResult; + + // check if ORowSetValue type is given + // when no types are given then we have to return all tables e.g. TABLE + + OUString aTable("TABLE"); + + bool bTableFound = true; + sal_Int32 nLength = types.getLength(); + if(nLength) + { + bTableFound = false; + + const OUString* pIter = types.getConstArray(); + const OUString* pEnd = pIter + nLength; + for(;pIter != pEnd;++pIter) + { + if(*pIter == aTable) + { + bTableFound = true; + break; + } + } + } + if(!bTableFound) + return xRef; + + // get the sheet names from the document + + OCalcConnection::ODocHolder aDocHolder(static_cast<OCalcConnection*>(m_pConnection)); + const Reference<XSpreadsheetDocument>& xDoc = aDocHolder.getDoc(); + if ( !xDoc.is() ) + throw SQLException(); + Reference<XSpreadsheets> xSheets = xDoc->getSheets(); + if ( !xSheets.is() ) + throw SQLException(); + Sequence< OUString > aSheetNames = xSheets->getElementNames(); + + ODatabaseMetaDataResultSet::ORows aRows; + sal_Int32 nSheetCount = aSheetNames.getLength(); + for (sal_Int32 nSheet=0; nSheet<nSheetCount; nSheet++) + { + OUString aName = aSheetNames[nSheet]; + if ( !lcl_IsEmptyOrHidden( xSheets, aName ) && match(tableNamePattern,aName,'\0') ) + { + ODatabaseMetaDataResultSet::ORow aRow { nullptr, nullptr, nullptr }; + aRow.reserve(6); + aRow.push_back(new ORowSetValueDecorator(aName)); + aRow.push_back(new ORowSetValueDecorator(aTable)); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRows.push_back(aRow); + } + } + + // also use database ranges + + Reference<XPropertySet> xDocProp( xDoc, UNO_QUERY ); + if ( xDocProp.is() ) + { + Any aRangesAny = xDocProp->getPropertyValue("DatabaseRanges"); + Reference<XDatabaseRanges> xRanges; + if ( aRangesAny >>= xRanges ) + { + Sequence< OUString > aDBNames = xRanges->getElementNames(); + sal_Int32 nDBCount = aDBNames.getLength(); + for (sal_Int32 nRange=0; nRange<nDBCount; nRange++) + { + OUString aName = aDBNames[nRange]; + if ( !lcl_IsUnnamed( xRanges, aName ) && match(tableNamePattern,aName,'\0') ) + { + ODatabaseMetaDataResultSet::ORow aRow { nullptr, nullptr, nullptr }; + aRow.reserve(6); + aRow.push_back(new ORowSetValueDecorator(aName)); + aRow.push_back(new ORowSetValueDecorator(aTable)); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRows.push_back(aRow); + } + } + } + } + + pResult->setRows(aRows); + + return xRef; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/calc/CDriver.cxx b/connectivity/source/drivers/calc/CDriver.cxx new file mode 100644 index 000000000..3b53ebccd --- /dev/null +++ b/connectivity/source/drivers/calc/CDriver.cxx @@ -0,0 +1,94 @@ +/* -*- 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 <calc/CDriver.hxx> +#include <calc/CConnection.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <connectivity/dbexception.hxx> +#include <resource/sharedresources.hxx> +#include <comphelper/processfactory.hxx> +#include <strings.hrc> + +using namespace connectivity::calc; +using namespace connectivity::file; +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::lang; + + +// static ServiceInfo + +OUString ODriver::getImplementationName_Static( ) +{ + return "com.sun.star.comp.sdbc.calc.ODriver"; +} + +OUString SAL_CALL ODriver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +// service names from file::OFileDriver + + +css::uno::Reference< css::uno::XInterface > + connectivity::calc::ODriver_CreateInstance(const css::uno::Reference< + css::lang::XMultiServiceFactory >& _rxFactory) +{ + return *(new ODriver( comphelper::getComponentContext(_rxFactory) )); +} + +Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url, + const Sequence< PropertyValue >& info ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (ODriver_BASE::rBHelper.bDisposed) + throw DisposedException(); + + if ( ! acceptsURL(url) ) + return nullptr; + + OCalcConnection* pCon = new OCalcConnection(this); + pCon->construct(url,info); + Reference< XConnection > xCon = pCon; + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + + return xCon; +} + +sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url ) +{ + return url.startsWith("sdbc:calc:"); +} + +Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) +{ + if ( !acceptsURL(url) ) + { + SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + return Sequence< DriverPropertyInfo >(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/calc/CTable.cxx b/connectivity/source/drivers/calc/CTable.cxx new file mode 100644 index 000000000..045ea5419 --- /dev/null +++ b/connectivity/source/drivers/calc/CTable.cxx @@ -0,0 +1,657 @@ +/* -*- 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 <calc/CTable.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sheet/XSpreadsheetDocument.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <com/sun/star/sheet/XCellRangeAddressable.hpp> +#include <com/sun/star/sheet/XCellRangesQuery.hpp> +#include <com/sun/star/sheet/XDatabaseRanges.hpp> +#include <com/sun/star/sheet/XDatabaseRange.hpp> +#include <com/sun/star/sheet/XCellRangeReferrer.hpp> +#include <com/sun/star/sheet/XUsedAreaCursor.hpp> +#include <com/sun/star/sheet/CellFlags.hpp> +#include <com/sun/star/sheet/FormulaResult.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/text/XText.hpp> +#include <calc/CConnection.hxx> +#include <connectivity/sdbcx/VColumn.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <rtl/math.hxx> +#include <tools/time.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> + +using namespace connectivity; +using namespace connectivity::calc; +using namespace connectivity::file; +using namespace ::cppu; +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; +using namespace ::com::sun::star::sheet; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::util; + + +static void lcl_UpdateArea( const Reference<XCellRange>& xUsedRange, sal_Int32& rEndCol, sal_Int32& rEndRow ) +{ + // update rEndCol, rEndRow if any non-empty cell in xUsedRange is right/below + + const Reference<XCellRangesQuery> xUsedQuery( xUsedRange, UNO_QUERY ); + if ( !xUsedQuery.is() ) + return; + + const sal_Int16 nContentFlags = + CellFlags::STRING | CellFlags::VALUE | CellFlags::DATETIME | CellFlags::FORMULA | CellFlags::ANNOTATION; + + const Reference<XSheetCellRanges> xUsedRanges = xUsedQuery->queryContentCells( nContentFlags ); + const Sequence<CellRangeAddress> aAddresses = xUsedRanges->getRangeAddresses(); + + const sal_Int32 nCount = aAddresses.getLength(); + const CellRangeAddress* pData = aAddresses.getConstArray(); + for ( sal_Int32 i=0; i<nCount; i++ ) + { + rEndCol = std::max(pData[i].EndColumn, rEndCol); + rEndRow = std::max(pData[i].EndRow, rEndRow); + } +} + +static void lcl_GetDataArea( const Reference<XSpreadsheet>& xSheet, sal_Int32& rColumnCount, sal_Int32& rRowCount ) +{ + Reference<XSheetCellCursor> xCursor = xSheet->createCursor(); + Reference<XCellRangeAddressable> xRange( xCursor, UNO_QUERY ); + if ( !xRange.is() ) + { + rColumnCount = rRowCount = 0; + return; + } + + // first find the contiguous cell area starting at A1 + + xCursor->collapseToSize( 1, 1 ); // single (first) cell + xCursor->collapseToCurrentRegion(); // contiguous data area + + CellRangeAddress aRegionAddr = xRange->getRangeAddress(); + sal_Int32 nEndCol = aRegionAddr.EndColumn; + sal_Int32 nEndRow = aRegionAddr.EndRow; + + Reference<XUsedAreaCursor> xUsed( xCursor, UNO_QUERY ); + if ( xUsed.is() ) + { + // The used area from XUsedAreaCursor includes visible attributes. + // If the used area is larger than the contiguous cell area, find non-empty + // cells in that area. + + xUsed->gotoEndOfUsedArea( false ); + CellRangeAddress aUsedAddr = xRange->getRangeAddress(); + + if ( aUsedAddr.EndColumn > aRegionAddr.EndColumn ) + { + Reference<XCellRange> xUsedRange = xSheet->getCellRangeByPosition( + aRegionAddr.EndColumn + 1, 0, aUsedAddr.EndColumn, aUsedAddr.EndRow ); + lcl_UpdateArea( xUsedRange, nEndCol, nEndRow ); + } + + if ( aUsedAddr.EndRow > aRegionAddr.EndRow ) + { + // only up to the last column of aRegionAddr, the other columns are handled above + Reference<XCellRange> xUsedRange = xSheet->getCellRangeByPosition( + 0, aRegionAddr.EndRow + 1, aRegionAddr.EndColumn, aUsedAddr.EndRow ); + lcl_UpdateArea( xUsedRange, nEndCol, nEndRow ); + } + } + + rColumnCount = nEndCol + 1; // number of columns + rRowCount = nEndRow; // first row (headers) is not counted +} + +static CellContentType lcl_GetContentOrResultType( const Reference<XCell>& xCell ) +{ + CellContentType eCellType = xCell->getType(); + if ( eCellType == CellContentType_FORMULA ) + { + Reference<XPropertySet> xProp( xCell, UNO_QUERY ); + try + { + xProp->getPropertyValue( "CellContentType" ) >>= eCellType; // type of cell content + } + catch (UnknownPropertyException&) + { + eCellType = CellContentType_VALUE; // if CellContentType property not available + } + } + return eCellType; +} + +static Reference<XCell> lcl_GetUsedCell( const Reference<XSpreadsheet>& xSheet, sal_Int32 nDocColumn, sal_Int32 nDocRow ) +{ + Reference<XCell> xCell = xSheet->getCellByPosition( nDocColumn, nDocRow ); + if ( xCell.is() && xCell->getType() == CellContentType_EMPTY ) + { + // get first non-empty cell + + Reference<XCellRangeAddressable> xAddr( xSheet, UNO_QUERY ); + if (xAddr.is()) + { + CellRangeAddress aTotalRange = xAddr->getRangeAddress(); + sal_Int32 nLastRow = aTotalRange.EndRow; + Reference<XCellRangesQuery> xQuery( xSheet->getCellRangeByPosition( nDocColumn, nDocRow, nDocColumn, nLastRow ), UNO_QUERY ); + if (xQuery.is()) + { + // queryIntersection to get a ranges object + Reference<XSheetCellRanges> xRanges = xQuery->queryIntersection( aTotalRange ); + if (xRanges.is()) + { + Reference<XEnumerationAccess> xCells = xRanges->getCells(); + if (xCells.is()) + { + Reference<XEnumeration> xEnum = xCells->createEnumeration(); + if ( xEnum.is() && xEnum->hasMoreElements() ) + { + // get first non-empty cell from enumeration + xCell.set(xEnum->nextElement(),UNO_QUERY); + } + // otherwise, keep empty cell + } + } + } + } + } + return xCell; +} + +static bool lcl_HasTextInColumn( const Reference<XSpreadsheet>& xSheet, sal_Int32 nDocColumn, sal_Int32 nDocRow ) +{ + // look for any text cell or text result in the column + + Reference<XCellRangeAddressable> xAddr( xSheet, UNO_QUERY ); + if (xAddr.is()) + { + CellRangeAddress aTotalRange = xAddr->getRangeAddress(); + sal_Int32 nLastRow = aTotalRange.EndRow; + Reference<XCellRangesQuery> xQuery( xSheet->getCellRangeByPosition( nDocColumn, nDocRow, nDocColumn, nLastRow ), UNO_QUERY ); + if (xQuery.is()) + { + // are there text cells in the column? + Reference<XSheetCellRanges> xTextContent = xQuery->queryContentCells( CellFlags::STRING ); + if ( xTextContent.is() && xTextContent->hasElements() ) + return true; + + // are there formulas with text results in the column? + Reference<XSheetCellRanges> xTextFormula = xQuery->queryFormulaCells( FormulaResult::STRING ); + if ( xTextFormula.is() && xTextFormula->hasElements() ) + return true; + } + } + + return false; +} + +static void lcl_GetColumnInfo( const Reference<XSpreadsheet>& xSheet, const Reference<XNumberFormats>& xFormats, + sal_Int32 nDocColumn, sal_Int32 nStartRow, bool bHasHeaders, + OUString& rName, sal_Int32& rDataType, bool& rCurrency ) +{ + //! avoid duplicate field names + + // get column name from first row, if range contains headers + + if ( bHasHeaders ) + { + Reference<XText> xHeaderText( xSheet->getCellByPosition( nDocColumn, nStartRow ), UNO_QUERY ); + if ( xHeaderText.is() ) + rName = xHeaderText->getString(); + } + + // get column type from first data row + + sal_Int32 nDataRow = nStartRow; + if ( bHasHeaders ) + ++nDataRow; + Reference<XCell> xDataCell = lcl_GetUsedCell( xSheet, nDocColumn, nDataRow ); + + Reference<XPropertySet> xProp( xDataCell, UNO_QUERY ); + if ( !xProp.is() ) + return; + + rCurrency = false; // set to true for currency below + + const CellContentType eCellType = lcl_GetContentOrResultType( xDataCell ); + // #i35178# use "text" type if there is any text cell in the column + if ( eCellType == CellContentType_TEXT || lcl_HasTextInColumn( xSheet, nDocColumn, nDataRow ) ) + rDataType = DataType::VARCHAR; + else if ( eCellType == CellContentType_VALUE ) + { + // get number format to distinguish between different types + + sal_Int16 nNumType = NumberFormat::NUMBER; + try + { + sal_Int32 nKey = 0; + + if ( xProp->getPropertyValue( "NumberFormat" ) >>= nKey ) + { + const Reference<XPropertySet> xFormat = xFormats->getByKey( nKey ); + if ( xFormat.is() ) + { + xFormat->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE) ) >>= nNumType; + } + } + } + catch ( Exception& ) + { + } + + if ( nNumType & NumberFormat::TEXT ) + rDataType = DataType::VARCHAR; + else if ( nNumType & NumberFormat::NUMBER ) + rDataType = DataType::DECIMAL; + else if ( nNumType & NumberFormat::CURRENCY ) + { + rCurrency = true; + rDataType = DataType::DECIMAL; + } + else if ( ( nNumType & NumberFormat::DATETIME ) == NumberFormat::DATETIME ) + { + // NumberFormat::DATETIME is DATE | TIME + rDataType = DataType::TIMESTAMP; + } + else if ( nNumType & NumberFormat::DATE ) + rDataType = DataType::DATE; + else if ( nNumType & NumberFormat::TIME ) + rDataType = DataType::TIME; + else if ( nNumType & NumberFormat::LOGICAL ) + rDataType = DataType::BIT; + else + rDataType = DataType::DECIMAL; + } + else + { + // whole column empty + rDataType = DataType::VARCHAR; + } +} + + +static void lcl_SetValue( ORowSetValue& rValue, const Reference<XSpreadsheet>& xSheet, + sal_Int32 nStartCol, sal_Int32 nStartRow, bool bHasHeaders, + const ::Date& rNullDate, + sal_Int32 nDBRow, sal_Int32 nDBColumn, sal_Int32 nType ) +{ + sal_Int32 nDocColumn = nStartCol + nDBColumn - 1; // database counts from 1 + sal_Int32 nDocRow = nStartRow + nDBRow - 1; + if (bHasHeaders) + ++nDocRow; + + const Reference<XCell> xCell = xSheet->getCellByPosition( nDocColumn, nDocRow ); + if ( !xCell.is() ) + return; + + CellContentType eCellType = lcl_GetContentOrResultType( xCell ); + switch (nType) + { + case DataType::VARCHAR: + if ( eCellType == CellContentType_EMPTY ) + rValue.setNull(); + else + { + // #i25840# still let Calc convert numbers to text + const Reference<XText> xText( xCell, UNO_QUERY ); + if ( xText.is() ) + rValue = xText->getString(); + } + break; + case DataType::DECIMAL: + if ( eCellType == CellContentType_VALUE ) + rValue = xCell->getValue(); // double + else + rValue.setNull(); + break; + case DataType::BIT: + if ( eCellType == CellContentType_VALUE ) + rValue = xCell->getValue() != 0.0; + else + rValue.setNull(); + break; + case DataType::DATE: + if ( eCellType == CellContentType_VALUE ) + { + ::Date aDate( rNullDate ); + aDate.AddDays(::rtl::math::approxFloor( xCell->getValue() )); + rValue = aDate.GetUNODate(); + } + else + rValue.setNull(); + break; + case DataType::TIME: + if ( eCellType == CellContentType_VALUE ) + { + double fCellVal = xCell->getValue(); + double fTime = fCellVal - rtl::math::approxFloor( fCellVal ); + sal_Int64 nIntTime = static_cast<sal_Int64>(rtl::math::round( fTime * static_cast<double>(::tools::Time::nanoSecPerDay) )); + if ( nIntTime == ::tools::Time::nanoSecPerDay) + nIntTime = 0; // 23:59:59.9999999995 and above is 00:00:00.00 + css::util::Time aTime; + aTime.NanoSeconds = static_cast<sal_uInt32>( nIntTime % ::tools::Time::nanoSecPerSec ); + nIntTime /= ::tools::Time::nanoSecPerSec; + aTime.Seconds = static_cast<sal_uInt16>( nIntTime % 60 ); + nIntTime /= 60; + aTime.Minutes = static_cast<sal_uInt16>( nIntTime % 60 ); + nIntTime /= 60; + OSL_ENSURE( nIntTime < 24, "error in time calculation" ); + aTime.Hours = static_cast<sal_uInt16>(nIntTime); + rValue = aTime; + } + else + rValue.setNull(); + break; + case DataType::TIMESTAMP: + if ( eCellType == CellContentType_VALUE ) + { + double fCellVal = xCell->getValue(); + double fDays = ::rtl::math::approxFloor( fCellVal ); + double fTime = fCellVal - fDays; + long nIntDays = static_cast<long>(fDays); + sal_Int64 nIntTime = ::rtl::math::round( fTime * static_cast<double>(::tools::Time::nanoSecPerDay) ); + if ( nIntTime == ::tools::Time::nanoSecPerDay ) + { + nIntTime = 0; // 23:59:59.9999999995 and above is 00:00:00.00 + ++nIntDays; // (next day) + } + + css::util::DateTime aDateTime; + + aDateTime.NanoSeconds = static_cast<sal_uInt16>( nIntTime % ::tools::Time::nanoSecPerSec ); + nIntTime /= ::tools::Time::nanoSecPerSec; + aDateTime.Seconds = static_cast<sal_uInt16>( nIntTime % 60 ); + nIntTime /= 60; + aDateTime.Minutes = static_cast<sal_uInt16>( nIntTime % 60 ); + nIntTime /= 60; + OSL_ENSURE( nIntTime < 24, "error in time calculation" ); + aDateTime.Hours = static_cast<sal_uInt16>(nIntTime); + + ::Date aDate( rNullDate ); + aDate.AddDays( nIntDays ); + aDateTime.Day = aDate.GetDay(); + aDateTime.Month = aDate.GetMonth(); + aDateTime.Year = aDate.GetYear(); + + rValue = aDateTime; + } + else + rValue.setNull(); + break; + } // switch (nType) + +// rValue.setTypeKind(nType); +} + + +static OUString lcl_GetColumnStr( sal_Int32 nColumn ) +{ + if ( nColumn < 26 ) + return OUString( static_cast<sal_Unicode>( 'A' + nColumn ) ); + else + { + OUStringBuffer aBuffer(2); + aBuffer.setLength( 2 ); + aBuffer[0] = static_cast<sal_Unicode>( 'A' + ( nColumn / 26 ) - 1 ); + aBuffer[1] = static_cast<sal_Unicode>( 'A' + ( nColumn % 26 ) ); + return aBuffer.makeStringAndClear(); + } +} + +void OCalcTable::fillColumns() +{ + if ( !m_xSheet.is() ) + throw SQLException(); + + OUString aTypeName; + ::comphelper::UStringMixEqual aCase(m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()); + const bool bStoresMixedCaseQuotedIdentifiers = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(); + + for (sal_Int32 i = 0; i < m_nDataCols; i++) + { + OUString aColumnName; + sal_Int32 eType = DataType::OTHER; + bool bCurrency = false; + + lcl_GetColumnInfo( m_xSheet, m_xFormats, m_nStartCol + i, m_nStartRow, m_bHasHeaders, + aColumnName, eType, bCurrency ); + + if ( aColumnName.isEmpty() ) + aColumnName = lcl_GetColumnStr( i ); + + sal_Int32 nPrecision = 0; //! ... + sal_Int32 nDecimals = 0; //! ... + + switch ( eType ) + { + case DataType::VARCHAR: + aTypeName = "VARCHAR"; + break; + case DataType::DECIMAL: + aTypeName = "DECIMAL"; + break; + case DataType::BIT: + aTypeName = "BOOL"; + break; + case DataType::DATE: + aTypeName = "DATE"; + break; + case DataType::TIME: + aTypeName = "TIME"; + break; + case DataType::TIMESTAMP: + aTypeName = "TIMESTAMP"; + break; + default: + SAL_WARN( "connectivity.drivers","missing type name"); + aTypeName.clear(); + } + + // check if the column name already exists + OUString aAlias = aColumnName; + OSQLColumns::const_iterator aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase); + sal_Int32 nExprCnt = 0; + while(aFind != m_aColumns->end()) + { + aAlias = aColumnName + OUString::number(++nExprCnt); + aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase); + } + + sdbcx::OColumn* pColumn = new sdbcx::OColumn( aAlias, aTypeName, OUString(),OUString(), + ColumnValue::NULLABLE, nPrecision, nDecimals, + eType, false, false, bCurrency, + bStoresMixedCaseQuotedIdentifiers, + m_CatalogName, getSchema(), getName()); + Reference< XPropertySet> xCol = pColumn; + m_aColumns->push_back(xCol); + m_aTypes.push_back(eType); + } +} + + +OCalcTable::OCalcTable(sdbcx::OCollection* _pTables,OCalcConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName + ) : OCalcTable_BASE(_pTables,_pConnection,Name, + Type, + Description, + SchemaName, + CatalogName) + ,m_pCalcConnection(_pConnection) + ,m_nStartCol(0) + ,m_nStartRow(0) + ,m_nDataCols(0) + ,m_bHasHeaders(false) + ,m_aNullDate(::Date::EMPTY) +{ +} + +void OCalcTable::construct() +{ + // get sheet object + Reference< XSpreadsheetDocument> xDoc = m_pCalcConnection->acquireDoc(); + if (xDoc.is()) + { + Reference<XSpreadsheets> xSheets = xDoc->getSheets(); + if ( xSheets.is() && xSheets->hasByName( m_Name ) ) + { + m_xSheet.set(xSheets->getByName( m_Name ),UNO_QUERY); + if ( m_xSheet.is() ) + { + lcl_GetDataArea( m_xSheet, m_nDataCols, m_nDataRows ); + m_bHasHeaders = true; + // whole sheet is always assumed to include a header row + } + } + else // no sheet -> try database range + { + Reference<XPropertySet> xDocProp( xDoc, UNO_QUERY ); + if ( xDocProp.is() ) + { + Reference<XDatabaseRanges> xRanges(xDocProp->getPropertyValue("DatabaseRanges"),UNO_QUERY); + + if ( xRanges.is() && xRanges->hasByName( m_Name ) ) + { + Reference<XDatabaseRange> xDBRange(xRanges->getByName( m_Name ),UNO_QUERY); + Reference<XCellRangeReferrer> xRefer( xDBRange, UNO_QUERY ); + if ( xRefer.is() ) + { + // Header flag is always stored with database range + // Get flag from FilterDescriptor + + bool bRangeHeader = true; + Reference<XPropertySet> xFiltProp( xDBRange->getFilterDescriptor(), UNO_QUERY ); + if ( xFiltProp.is() ) + xFiltProp->getPropertyValue("ContainsHeader") >>= bRangeHeader; + + Reference<XSheetCellRange> xSheetRange( xRefer->getReferredCells(), UNO_QUERY ); + Reference<XCellRangeAddressable> xAddr( xSheetRange, UNO_QUERY ); + if ( xSheetRange.is() && xAddr.is() ) + { + m_xSheet = xSheetRange->getSpreadsheet(); + CellRangeAddress aRangeAddr = xAddr->getRangeAddress(); + m_nStartCol = aRangeAddr.StartColumn; + m_nStartRow = aRangeAddr.StartRow; + m_nDataCols = aRangeAddr.EndColumn - m_nStartCol + 1; + // m_nDataRows is excluding header row + m_nDataRows = aRangeAddr.EndRow - m_nStartRow; + if ( !bRangeHeader ) + { + // m_nDataRows counts the whole range + m_nDataRows += 1; + } + + m_bHasHeaders = bRangeHeader; + } + } + } + } + } + + Reference<XNumberFormatsSupplier> xSupp( xDoc, UNO_QUERY ); + if (xSupp.is()) + m_xFormats = xSupp->getNumberFormats(); + + Reference<XPropertySet> xProp( xDoc, UNO_QUERY ); + if (xProp.is()) + { + css::util::Date aDateStruct; + if ( xProp->getPropertyValue("NullDate") >>= aDateStruct ) + m_aNullDate = ::Date( aDateStruct.Day, aDateStruct.Month, aDateStruct.Year ); + } + } + + //! default if no null date available? + + fillColumns(); + + refreshColumns(); +} + +void SAL_CALL OCalcTable::disposing() +{ + OFileTable::disposing(); + ::osl::MutexGuard aGuard(m_aMutex); + m_aColumns = nullptr; + if ( m_pCalcConnection ) + m_pCalcConnection->releaseDoc(); + m_pCalcConnection = nullptr; + +} + +Sequence< sal_Int8 > OCalcTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OCalcTable::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return (isUnoTunnelId<OCalcTable>(rId)) + ? reinterpret_cast< sal_Int64 >( this ) + : OCalcTable_BASE::getSomething(rId); +} + +bool OCalcTable::fetchRow( OValueRefRow& _rRow, const OSQLColumns & _rCols, + bool bRetrieveData ) +{ + // read the bookmark + + _rRow->setDeleted(false); + *(*_rRow)[0] = m_nFilePos; + + if (!bRetrieveData) + return true; + + // fields + + const OValueRefVector::size_type nCount = std::min(_rRow->size(), _rCols.size() + 1); + for (OValueRefVector::size_type i = 1; i < nCount; i++) + { + if ( (*_rRow)[i]->isBound() ) + { + sal_Int32 nType = m_aTypes[i-1]; + + lcl_SetValue( (*_rRow)[i]->get(), m_xSheet, m_nStartCol, m_nStartRow, m_bHasHeaders, + m_aNullDate, m_nFilePos, i, nType ); + } + } + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/calc/CTables.cxx b/connectivity/source/drivers/calc/CTables.cxx new file mode 100644 index 000000000..703ab2712 --- /dev/null +++ b/connectivity/source/drivers/calc/CTables.cxx @@ -0,0 +1,49 @@ +/* -*- 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 <calc/CConnection.hxx> +#include <calc/CTables.hxx> +#include <calc/CTable.hxx> +#include <file/FCatalog.hxx> +#include <file/FConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::calc; +using namespace connectivity::file; +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::lang; +using namespace ::com::sun::star::container; + +sdbcx::ObjectType OCalcTables::createObject(const OUString& _rName) +{ + OCalcTable* pTable = new OCalcTable(this, static_cast<OCalcConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection()), + _rName,"TABLE"); + sdbcx::ObjectType xRet = pTable; + pTable->construct(); + return xRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/calc/Cservices.cxx b/connectivity/source/drivers/calc/Cservices.cxx new file mode 100644 index 000000000..06a516ddc --- /dev/null +++ b/connectivity/source/drivers/calc/Cservices.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 <calc/CDriver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::calc; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* connectivity_calc_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + ODriver::getImplementationName_Static(), + ODriver::getSupportedServiceNames_Static(), + ODriver_CreateInstance, ::cppu::createSingleFactory) + ; + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/calc/calc.component b/connectivity/source/drivers/calc/calc.component new file mode 100644 index 000000000..ffbddfa34 --- /dev/null +++ b/connectivity/source/drivers/calc/calc.component @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="connectivity_calc" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.calc.ODriver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/component/CColumns.cxx b/connectivity/source/drivers/component/CColumns.cxx new file mode 100644 index 000000000..9f802b6e4 --- /dev/null +++ b/connectivity/source/drivers/component/CColumns.cxx @@ -0,0 +1,44 @@ +/* -*- 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 <component/CColumns.hxx> +#include <file/FTable.hxx> + +using namespace connectivity::component; +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; + + +sdbcx::ObjectType OComponentColumns::createObject(const OUString& _rName) +{ + ::rtl::Reference<OSQLColumns> aCols = m_pTable->getTableColumns(); + + OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive())); + sdbcx::ObjectType xRet; + if(aIter != aCols->end()) + xRet = sdbcx::ObjectType(*aIter,UNO_QUERY); + return xRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/component/CDatabaseMetaData.cxx b/connectivity/source/drivers/component/CDatabaseMetaData.cxx new file mode 100644 index 000000000..f225747a6 --- /dev/null +++ b/connectivity/source/drivers/component/CDatabaseMetaData.cxx @@ -0,0 +1,244 @@ +/* -*- 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 <component/CDatabaseMetaData.hxx> +#include <file/FConnection.hxx> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <FDatabaseMetaDataResultSet.hxx> +#include <comphelper/types.hxx> + +using namespace connectivity::component; +using namespace connectivity::file; +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; + +OComponentDatabaseMetaData::OComponentDatabaseMetaData(OConnection* _pCon) :ODatabaseMetaData(_pCon) +{ +} + +OComponentDatabaseMetaData::~OComponentDatabaseMetaData() +{ +} + +Reference< XResultSet > OComponentDatabaseMetaData::impl_getTypeInfo_throw( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo); + Reference< XResultSet > xRef = pResult; + + static ODatabaseMetaDataResultSet::ORows aRows; + if(aRows.empty()) + { + ODatabaseMetaDataResultSet::ORow aRow; + + aRows.reserve(6); + aRow.reserve(18); + + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(OUString("VARCHAR"))); + aRow.push_back(new ORowSetValueDecorator(DataType::VARCHAR)); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(65535))); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); // ORowSetValue((sal_Int32)ColumnValue::NULLABLE) + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR))); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(10))); + + + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL")); + aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL); + aRow[3] = ODatabaseMetaDataResultSet::get0Value(); + aRow[9] = ODatabaseMetaDataResultSet::getBasicValue(); + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("BOOL")); + aRow[2] = new ORowSetValueDecorator(DataType::BIT); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[9] = ODatabaseMetaDataResultSet::getBasicValue(); + aRow[15] = new ORowSetValueDecorator(sal_Int32(15)); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DATE")); + aRow[2] = new ORowSetValueDecorator(DataType::DATE); + aRow[3] = ODatabaseMetaDataResultSet::get0Value(); + aRow[9] = ODatabaseMetaDataResultSet::getBasicValue(); + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("TIME")); + aRow[2] = new ORowSetValueDecorator(DataType::TIME); + aRow[3] = ODatabaseMetaDataResultSet::get0Value(); + aRow[9] = ODatabaseMetaDataResultSet::getBasicValue(); + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP")); + aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP); + aRow[3] = ODatabaseMetaDataResultSet::get0Value(); + aRow[9] = ODatabaseMetaDataResultSet::getBasicValue(); + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); + aRows.push_back(aRow); + } + + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL OComponentDatabaseMetaData::getColumns( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + + Reference< XTablesSupplier > xTables = m_pConnection->createCatalog(); + if(!xTables.is()) + throw SQLException(); + + Reference< XNameAccess> xNames = xTables->getTables(); + if(!xNames.is()) + throw SQLException(); + + ODatabaseMetaDataResultSet::ORows aRows; + ODatabaseMetaDataResultSet::ORow aRow(19); + + aRow[10] = new ORowSetValueDecorator(sal_Int32(10)); + + Sequence< OUString> aTabNames(xNames->getElementNames()); + const OUString* pTabIter = aTabNames.getConstArray(); + const OUString* pTabEnd = pTabIter + aTabNames.getLength(); + for(;pTabIter != pTabEnd;++pTabIter) + { + if(match(tableNamePattern,*pTabIter,'\0')) + { + const Reference< XColumnsSupplier> xTable(xNames->getByName(*pTabIter),UNO_QUERY_THROW); + aRow[3] = new ORowSetValueDecorator(*pTabIter); + + const Reference< XNameAccess> xColumns = xTable->getColumns(); + if(!xColumns.is()) + throw SQLException(); + + const Sequence< OUString> aColNames(xColumns->getElementNames()); + + const OUString* pColumnIter = aColNames.getConstArray(); + const OUString* pEnd = pColumnIter + aColNames.getLength(); + Reference< XPropertySet> xColumn; + for(sal_Int32 i=1;pColumnIter != pEnd;++pColumnIter,++i) + { + if(match(columnNamePattern,*pColumnIter,'\0')) + { + aRow[4] = new ORowSetValueDecorator( *pColumnIter); + + xColumns->getByName(*pColumnIter) >>= xColumn; + OSL_ENSURE(xColumn.is(),"Columns contains a column who isn't a fastpropertyset!"); + aRow[5] = new ORowSetValueDecorator(::comphelper::getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))); + aRow[6] = new ORowSetValueDecorator(::comphelper::getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))); + aRow[7] = new ORowSetValueDecorator(::comphelper::getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))); + // aRow[8] = xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)); + aRow[9] = new ORowSetValueDecorator(::comphelper::getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))); + aRow[11] = new ORowSetValueDecorator(::comphelper::getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))); + // aRow[12] = xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)); + aRow[13] = new ORowSetValueDecorator(::comphelper::getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))); + // aRow[14] = xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)); + // aRow[15] = xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)); + switch(sal_Int32(aRow[5]->getValue())) + { + case DataType::CHAR: + case DataType::VARCHAR: + aRow[16] = new ORowSetValueDecorator(sal_Int32(254)); + break; + case DataType::LONGVARCHAR: + aRow[16] = new ORowSetValueDecorator(sal_Int32(65535)); + break; + default: + aRow[16] = new ORowSetValueDecorator(sal_Int32(0)); + } + aRow[17] = new ORowSetValueDecorator(i); + switch(sal_Int32(aRow[11]->getValue())) + { + case ColumnValue::NO_NULLS: + aRow[18] = new ORowSetValueDecorator(OUString("NO")); + break; + case ColumnValue::NULLABLE: + aRow[18] = new ORowSetValueDecorator(OUString("YES")); + break; + default: + aRow[18] = new ORowSetValueDecorator(OUString()); + } + aRows.push_back(aRow); + } + } + } + } + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns); + Reference< XResultSet > xRef = pResult; + pResult->setRows(aRows); + + return xRef; +} + +sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return SAL_MAX_INT32; +} + +sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxCharLiteralLength( ) +{ + return SAL_MAX_INT32; +} + +sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxColumnNameLength( ) +{ + return SAL_MAX_INT32; +} + +sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxColumnsInIndex( ) +{ + return 1; +} + +sal_Int32 SAL_CALL OComponentDatabaseMetaData::getMaxColumnsInTable( ) +{ + return 256; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/component/CPreparedStatement.cxx b/connectivity/source/drivers/component/CPreparedStatement.cxx new file mode 100644 index 000000000..bc3af3e8c --- /dev/null +++ b/connectivity/source/drivers/component/CPreparedStatement.cxx @@ -0,0 +1,34 @@ +/* -*- 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 <component/CPreparedStatement.hxx> +#include <component/CResultSet.hxx> + +using namespace connectivity::component; +using namespace connectivity::file; +using namespace com::sun::star::uno; + +OResultSet* OComponentPreparedStatement::createResultSet() +{ + return new connectivity::component::OComponentResultSet(this,m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(OComponentPreparedStatement,"com.sun.star.sdbc.driver.component.PreparedStatement","com.sun.star.sdbc.PreparedStatement"); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/component/CResultSet.cxx b/connectivity/source/drivers/component/CResultSet.cxx new file mode 100644 index 000000000..050b4034d --- /dev/null +++ b/connectivity/source/drivers/component/CResultSet.cxx @@ -0,0 +1,172 @@ +/* -*- 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 <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <component/CResultSet.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/dbexception.hxx> + +using namespace ::comphelper; +using namespace connectivity::component; +using namespace connectivity::file; +using namespace ::cppu; +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::sdbcx; + + +OComponentResultSet::OComponentResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator) + : file::OResultSet(pStmt,_aSQLIterator) + ,m_bBookmarkable(true) +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), PROPERTY_ID_ISBOOKMARKABLE, PropertyAttribute::READONLY,&m_bBookmarkable, cppu::UnoType<bool>::get()); +} + +OUString SAL_CALL OComponentResultSet::getImplementationName( ) +{ + return "com.sun.star.sdbcx.component.ResultSet"; +} + +Sequence< OUString > SAL_CALL OComponentResultSet::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL OComponentResultSet::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Any SAL_CALL OComponentResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OResultSet::queryInterface(rType); + return aRet.hasValue() ? aRet : OComponentResultSet_BASE::queryInterface(rType); +} + + Sequence< Type > SAL_CALL OComponentResultSet::getTypes( ) +{ + return ::comphelper::concatSequences(OResultSet::getTypes(),OComponentResultSet_BASE::getTypes()); +} + + +// XRowLocate +Any SAL_CALL OComponentResultSet::getBookmark( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return makeAny(static_cast<sal_Int32>((*m_aRow)[0]->getValue())); +} + +sal_Bool SAL_CALL OComponentResultSet::moveToBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false; + + return Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),true); +} + +sal_Bool SAL_CALL OComponentResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false; + + Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),false); + + return relative(rows); +} + + +sal_Int32 SAL_CALL OComponentResultSet::compareBookmarks( const Any& lhs, const Any& rhs ) +{ + return (lhs == rhs) ? CompareBookmark::EQUAL : CompareBookmark::NOT_EQUAL; +} + +sal_Bool SAL_CALL OComponentResultSet::hasOrderedBookmarks( ) +{ + return true; +} + +sal_Int32 SAL_CALL OComponentResultSet::hashBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return comphelper::getINT32(bookmark); +} + +// XDeleteRows +Sequence< sal_Int32 > SAL_CALL OComponentResultSet::deleteRows( const Sequence< Any >& /*rows*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFeatureNotImplementedSQLException( "XDeleteRows::deleteRows", *this ); + return Sequence< sal_Int32 >(); +} + +bool OComponentResultSet::fillIndexValues(const Reference< XColumnsSupplier> &/*_xIndex*/) +{ + // Writer or Calc table has no index + return false; +} + +::cppu::IPropertyArrayHelper & OComponentResultSet::getInfoHelper() +{ + return *OComponentResultSet_BASE3::getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* OComponentResultSet::createArrayHelper() const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + + +void SAL_CALL OComponentResultSet::acquire() throw() +{ + OComponentResultSet_BASE2::acquire(); +} + +void SAL_CALL OComponentResultSet::release() throw() +{ + OComponentResultSet_BASE2::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OComponentResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/component/CStatement.cxx b/connectivity/source/drivers/component/CStatement.cxx new file mode 100644 index 000000000..8adfefae8 --- /dev/null +++ b/connectivity/source/drivers/component/CStatement.cxx @@ -0,0 +1,34 @@ +/* -*- 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 <component/CStatement.hxx> +#include <component/CResultSet.hxx> + +using namespace connectivity::component; +using namespace connectivity::file; +using namespace com::sun::star::uno; + +OResultSet* OComponentStatement::createResultSet() +{ + return new connectivity::component::OComponentResultSet(this,m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(OComponentStatement,"com.sun.star.sdbc.driver.component.Statement","com.sun.star.sdbc.Statement"); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/component/CTable.cxx b/connectivity/source/drivers/component/CTable.cxx new file mode 100644 index 000000000..9b5354d26 --- /dev/null +++ b/connectivity/source/drivers/component/CTable.cxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <component/CTable.hxx> +#include <component/CColumns.hxx> +#include <cppuhelper/queryinterface.hxx> + +using namespace connectivity; +using namespace connectivity::component; +using namespace connectivity::file; +using namespace ::cppu; +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; +using namespace ::com::sun::star::sheet; +using namespace ::com::sun::star::util; + + +OComponentTable::OComponentTable(sdbcx::OCollection* _pTables,file::OConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName + ) : OComponentTable_BASE(_pTables,_pConnection,Name, + Type, + Description, + SchemaName, + CatalogName) + ,m_nDataRows(0) +{ +} + +void OComponentTable::refreshColumns() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::std::vector< OUString> aVector; + + for(const auto& rxColumn : *m_aColumns) + aVector.push_back(Reference< XNamed>(rxColumn,UNO_QUERY_THROW)->getName()); + + if(m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns = new component::OComponentColumns(this,m_aMutex,aVector); +} + +void OComponentTable::refreshIndexes() +{ + // Writer or Calc table has no index +} + + +Sequence< Type > SAL_CALL OComponentTable::getTypes( ) +{ + Sequence< Type > aTypes = OTable_TYPEDEF::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!( *pBegin == cppu::UnoType<XKeysSupplier>::get()|| + *pBegin == cppu::UnoType<XIndexesSupplier>::get()|| + *pBegin == cppu::UnoType<XRename>::get()|| + *pBegin == cppu::UnoType<XAlterTable>::get()|| + *pBegin == cppu::UnoType<XDataDescriptorFactory>::get())) + aOwnTypes.push_back(*pBegin); + } + aOwnTypes.push_back(cppu::UnoType<css::lang::XUnoTunnel>::get()); + + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +Any SAL_CALL OComponentTable::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType<XKeysSupplier>::get()|| + rType == cppu::UnoType<XIndexesSupplier>::get()|| + rType == cppu::UnoType<XRename>::get()|| + rType == cppu::UnoType<XAlterTable>::get()|| + rType == cppu::UnoType<XDataDescriptorFactory>::get()) + return Any(); + + const Any aRet = ::cppu::queryInterface(rType,static_cast< css::lang::XUnoTunnel*> (this)); + return aRet.hasValue() ? aRet : OTable_TYPEDEF::queryInterface(rType); +} + + +sal_Int32 OComponentTable::getCurrentLastPos() const +{ + return m_nDataRows; +} + +bool OComponentTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) +{ + // prepare positioning: + + sal_uInt32 nNumberOfRecords = m_nDataRows; + sal_uInt32 nTempPos = m_nFilePos; + m_nFilePos = nCurPos; + + switch(eCursorPosition) + { + case IResultSetHelper::NEXT: + m_nFilePos++; + break; + case IResultSetHelper::PRIOR: + if (m_nFilePos > 0) + m_nFilePos--; + break; + case IResultSetHelper::FIRST: + m_nFilePos = 1; + break; + case IResultSetHelper::LAST: + m_nFilePos = nNumberOfRecords; + break; + case IResultSetHelper::RELATIVE1: + m_nFilePos = (m_nFilePos + nOffset < 0) ? 0 + : static_cast<sal_uInt32>(m_nFilePos + nOffset); + break; + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::BOOKMARK: + m_nFilePos = static_cast<sal_uInt32>(nOffset); + break; + } + + if (m_nFilePos > static_cast<sal_Int32>(nNumberOfRecords)) + m_nFilePos = static_cast<sal_Int32>(nNumberOfRecords) + 1; + + if (m_nFilePos == 0 || m_nFilePos == static_cast<sal_Int32>(nNumberOfRecords) + 1) + { + switch(eCursorPosition) + { + case IResultSetHelper::PRIOR: + case IResultSetHelper::FIRST: + m_nFilePos = 0; + break; + case IResultSetHelper::LAST: + case IResultSetHelper::NEXT: + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::RELATIVE1: + if (nOffset > 0) + m_nFilePos = nNumberOfRecords + 1; + else if (nOffset < 0) + m_nFilePos = 0; + break; + case IResultSetHelper::BOOKMARK: + m_nFilePos = nTempPos; // previous position + break; + } + return false; + } + + //! read buffer / setup row object etc? + nCurPos = m_nFilePos; + return true; +} + +void OComponentTable::FileClose() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + OComponentTable_BASE::FileClose(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DCatalog.cxx b/connectivity/source/drivers/dbase/DCatalog.cxx new file mode 100644 index 000000000..c35af1f28 --- /dev/null +++ b/connectivity/source/drivers/dbase/DCatalog.cxx @@ -0,0 +1,59 @@ +/* -*- 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 <dbase/DCatalog.hxx> +#include <dbase/DConnection.hxx> +#include <dbase/DTables.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> + +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 connectivity::dbase; + +ODbaseCatalog::ODbaseCatalog(ODbaseConnection* _pCon) : file::OFileCatalog(_pCon) +{ +} + +void ODbaseCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + Sequence< OUString > aTypes; + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), + "%", "%", aTypes); + + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while(xResult->next()) + aVector.push_back(xRow->getString(3)); + } + if(m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset( new ODbaseTables(m_xMetaData,*this,m_aMutex,aVector) ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DColumns.cxx b/connectivity/source/drivers/dbase/DColumns.cxx new file mode 100644 index 000000000..b997ec8d9 --- /dev/null +++ b/connectivity/source/drivers/dbase/DColumns.cxx @@ -0,0 +1,77 @@ +/* -*- 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 <dbase/DColumns.hxx> +#include <dbase/DTable.hxx> +#include <connectivity/sdbcx/VColumn.hxx> + +using namespace connectivity::dbase; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; + +sdbcx::ObjectType ODbaseColumns::createObject(const OUString& _rName) +{ + ODbaseTable* pTable = static_cast<ODbaseTable*>(m_pTable); + + const ::rtl::Reference<OSQLColumns>& aCols = pTable->getTableColumns(); + OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive())); + + sdbcx::ObjectType xRet; + if(aIter != aCols->end()) + xRet = sdbcx::ObjectType(*aIter,UNO_QUERY); + return xRet; +} + + +void ODbaseColumns::impl_refresh() +{ + m_pTable->refreshColumns(); +} + +Reference< XPropertySet > ODbaseColumns::createDescriptor() +{ + return new sdbcx::OColumn(isCaseSensitive()); +} + + +// XAppend +sdbcx::ObjectType ODbaseColumns::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + if ( m_pTable->isNew() ) + return cloneDescriptor( descriptor ); + + m_pTable->addColumn( descriptor ); + return createObject( _rForName ); +} + + +// XDrop +void ODbaseColumns::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/) +{ + if(!m_pTable->isNew()) + m_pTable->dropColumn(_nPos); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DConnection.cxx b/connectivity/source/drivers/dbase/DConnection.cxx new file mode 100644 index 000000000..7c577b7c9 --- /dev/null +++ b/connectivity/source/drivers/dbase/DConnection.cxx @@ -0,0 +1,115 @@ +/* -*- 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 <dbase/DConnection.hxx> +#include <dbase/DDatabaseMetaData.hxx> +#include <dbase/DCatalog.hxx> +#include <dbase/DDriver.hxx> +#include <dbase/DPreparedStatement.hxx> +#include <dbase/DStatement.hxx> +#include <connectivity/dbexception.hxx> + +using namespace connectivity::dbase; +using namespace connectivity::file; + +typedef connectivity::file::OConnection OConnection_BASE; + + +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::lang; + +ODbaseConnection::ODbaseConnection(ODriver* _pDriver) : OConnection(_pDriver) +{ + m_aFilenameExtension = "dbf"; +} + +ODbaseConnection::~ODbaseConnection() +{ +} + +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(ODbaseConnection, "com.sun.star.sdbc.drivers.dbase.Connection", "com.sun.star.sdbc.Connection") + + +Reference< XDatabaseMetaData > SAL_CALL ODbaseConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new ODbaseDatabaseMetaData(this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +css::uno::Reference< XTablesSupplier > ODbaseConnection::createCatalog() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XTablesSupplier > xTab = m_xCatalog; + if(!xTab.is()) + { + ODbaseCatalog *pCat = new ODbaseCatalog(this); + xTab = pCat; + m_xCatalog = xTab; + } + return xTab; +} + +Reference< XStatement > SAL_CALL ODbaseConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + Reference< XStatement > xReturn = new ODbaseStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL ODbaseConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + ODbasePreparedStatement* pStmt = new ODbasePreparedStatement(this); + Reference< XPreparedStatement > xHoldAlive = pStmt; + pStmt->construct(sql); + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return pStmt; +} + +Reference< XPreparedStatement > SAL_CALL ODbaseConnection::prepareCall( const OUString& /*sql*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this ); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DDatabaseMetaData.cxx b/connectivity/source/drivers/dbase/DDatabaseMetaData.cxx new file mode 100644 index 000000000..b896e942c --- /dev/null +++ b/connectivity/source/drivers/dbase/DDatabaseMetaData.cxx @@ -0,0 +1,388 @@ +/* -*- 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 <dbase/DDatabaseMetaData.hxx> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XIndexesSupplier.hpp> +#include <FDatabaseMetaDataResultSet.hxx> +#include <dbase/DIndex.hxx> +#include <connectivity/FValue.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <ucbhelper/content.hxx> + +using namespace ::comphelper; +using namespace connectivity::dbase; +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::ucb; +using namespace ::com::sun::star::lang; + +ODbaseDatabaseMetaData::ODbaseDatabaseMetaData(::connectivity::file::OConnection* _pCon) :ODatabaseMetaData(_pCon) +{ +} + +ODbaseDatabaseMetaData::~ODbaseDatabaseMetaData() +{ +} + +Reference< XResultSet > ODbaseDatabaseMetaData::impl_getTypeInfo_throw( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo); + Reference< XResultSet > xRef = pResult; + + static ODatabaseMetaDataResultSet::ORows aRows; + if(aRows.empty()) + { + ODatabaseMetaDataResultSet::ORow aRow; + aRow.reserve(19); + + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(OUString("VARCHAR"))); + aRow.push_back(new ORowSetValueDecorator(DataType::VARCHAR)); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(254))); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(new ORowSetValueDecorator(OUString("length"))); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(ColumnValue::NULLABLE))); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(ColumnSearch::FULL))); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(new ORowSetValueDecorator(OUString("C"))); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(10))); + + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("LONGVARCHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::LONGVARCHAR); + aRow[3] = new ORowSetValueDecorator(sal_Int32(2147483647)); + aRow[6] = new ORowSetValueDecorator(); + aRow[13] = new ORowSetValueDecorator(OUString("M")); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DATE")); + aRow[2] = new ORowSetValueDecorator(DataType::DATE); + aRow[3] = new ORowSetValueDecorator(sal_Int32(10)); + aRow[13] = new ORowSetValueDecorator(OUString("D")); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("BOOLEAN")); + aRow[2] = new ORowSetValueDecorator(DataType::BIT); + aRow[3] = ODatabaseMetaDataResultSet::get1Value(); + aRow[4] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[5] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[6] = new ORowSetValueDecorator(OUString()); + aRow[9] = ODatabaseMetaDataResultSet::getBasicValue(); + aRow[13] = new ORowSetValueDecorator(OUString("L")); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE")); + aRow[2] = new ORowSetValueDecorator(DataType::DOUBLE); + aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); + aRow[13] = new ORowSetValueDecorator(OUString("B")); + aRows.push_back(aRow); + + aRow[11] = new ORowSetValueDecorator(true); + aRow[13] = new ORowSetValueDecorator(OUString("Y")); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP")); + aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP); + aRow[11] = new ORowSetValueDecorator(false); + aRow[13] = new ORowSetValueDecorator(OUString("T")); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("INTEGER")); + aRow[2] = new ORowSetValueDecorator(DataType::INTEGER); + aRow[3] = new ORowSetValueDecorator(sal_Int32(10)); + aRow[13] = new ORowSetValueDecorator(OUString("I")); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL")); + aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[6] = new ORowSetValueDecorator(OUString("length,scale")); + aRow[13] = new ORowSetValueDecorator(OUString("F")); + aRows.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC")); + aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL); + aRow[3] = new ORowSetValueDecorator(sal_Int32(16)); + aRow[13] = new ORowSetValueDecorator(OUString("N")); + aRow[15] = new ORowSetValueDecorator(sal_Int32(16)); + aRows.push_back(aRow); + } + + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL ODbaseDatabaseMetaData::getColumns( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XTablesSupplier > xTables = m_pConnection->createCatalog(); + if(!xTables.is()) + throw SQLException(); + + Reference< XNameAccess> xNames = xTables->getTables(); + if(!xNames.is()) + throw SQLException(); + + ODatabaseMetaDataResultSet::ORows aRows; + ODatabaseMetaDataResultSet::ORow aRow(19); + + try + { + aRow[10] = new ORowSetValueDecorator(sal_Int32(10)); + Sequence< OUString> aTabNames(xNames->getElementNames()); + const OUString* pTabBegin = aTabNames.getConstArray(); + const OUString* pTabEnd = pTabBegin + aTabNames.getLength(); + for(;pTabBegin != pTabEnd;++pTabBegin) + { + if(match(tableNamePattern,*pTabBegin,'\0')) + { + Reference< XColumnsSupplier> xTable( + xNames->getByName(*pTabBegin), css::uno::UNO_QUERY); + OSL_ENSURE(xTable.is(),"Table not found! Normally an exception had to be thrown here!"); + aRow[3] = new ORowSetValueDecorator(*pTabBegin); + + Reference< XNameAccess> xColumns = xTable->getColumns(); + if(!xColumns.is()) + throw SQLException(); + + Sequence< OUString> aColNames(xColumns->getElementNames()); + + const OUString* pBegin = aColNames.getConstArray(); + const OUString* pEnd = pBegin + aColNames.getLength(); + Reference< XPropertySet> xColumn; + for(sal_Int32 i=1;pBegin != pEnd;++pBegin,++i) + { + if(match(columnNamePattern,*pBegin,'\0')) + { + aRow[4] = new ORowSetValueDecorator(*pBegin); + + xColumn.set( + xColumns->getByName(*pBegin), css::uno::UNO_QUERY); + OSL_ENSURE(xColumn.is(),"Columns contains a column who isn't a fastpropertyset!"); + aRow[5] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))); + aRow[6] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))); + aRow[7] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))); + aRow[9] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))); + aRow[11] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))); + aRow[13] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))); + switch(static_cast<sal_Int32>(aRow[5]->getValue())) + { + case DataType::CHAR: + case DataType::VARCHAR: + aRow[16] = new ORowSetValueDecorator(sal_Int32(254)); + break; + case DataType::LONGVARCHAR: + aRow[16] = new ORowSetValueDecorator(sal_Int32(65535)); + break; + default: + aRow[16] = new ORowSetValueDecorator(sal_Int32(0)); + } + aRow[17] = new ORowSetValueDecorator(i); + switch(sal_Int32(aRow[11]->getValue())) + { + case ColumnValue::NO_NULLS: + aRow[18] = new ORowSetValueDecorator(OUString("NO")); + break; + case ColumnValue::NULLABLE: + aRow[18] = new ORowSetValueDecorator(OUString("YES")); + break; + default: + aRow[18] = new ORowSetValueDecorator(OUString()); + } + aRows.push_back(aRow); + } + } + } + } + } + catch (const WrappedTargetException& e) + { + SQLException aSql; + if (e.TargetException >>= aSql) + throw aSql; + throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException); + } + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns); + Reference< XResultSet > xRef = pResult; + pResult->setRows(aRows); + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODbaseDatabaseMetaData::getIndexInfo( + const Any& /*catalog*/, const OUString& /*schema*/, const OUString& table, + sal_Bool unique, sal_Bool /*approximate*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XTablesSupplier > xTables = m_pConnection->createCatalog(); + if(!xTables.is()) + throw SQLException(); + + Reference< XNameAccess> xNames = xTables->getTables(); + if(!xNames.is()) + throw SQLException(); + + ODatabaseMetaDataResultSet::ORows aRows; + ODatabaseMetaDataResultSet::ORow aRow(14); + + aRow[5] = new ORowSetValueDecorator(OUString()); + aRow[10] = new ORowSetValueDecorator(OUString("A")); + + Reference< XIndexesSupplier> xTable( + xNames->getByName(table), css::uno::UNO_QUERY); + aRow[3] = new ORowSetValueDecorator(table); + aRow[7] = new ORowSetValueDecorator(sal_Int32(3)); + + Reference< XNameAccess> xIndexes = xTable->getIndexes(); + if(!xIndexes.is()) + throw SQLException(); + + Sequence< OUString> aIdxNames(xIndexes->getElementNames()); + + const OUString* pBegin = aIdxNames.getConstArray(); + const OUString* pEnd = pBegin + aIdxNames.getLength(); + Reference< XPropertySet> xIndex; + for(;pBegin != pEnd;++pBegin) + { + xIndex.set(xIndexes->getByName(*pBegin), css::uno::UNO_QUERY); + OSL_ENSURE(xIndex.is(),"Indexes contains a column who isn't a fastpropertyset!"); + + if(unique && !getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE)))) + continue; + aRow[4] = new ORowSetValueDecorator(getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE)))); + aRow[6] = new ORowSetValueDecorator(*pBegin); + + auto pIndex = comphelper::getUnoTunnelImplementation<ODbaseIndex>(xIndex); + if(pIndex) + { + aRow[11] = new ORowSetValueDecorator(static_cast<sal_Int32>(pIndex->getHeader().db_maxkeys)); + aRow[12] = new ORowSetValueDecorator(static_cast<sal_Int32>(pIndex->getHeader().db_pagecount)); + } + + Reference<XColumnsSupplier> xColumnsSup(xIndex,UNO_QUERY); + Reference< XNameAccess> xColumns = xColumnsSup->getColumns(); + Sequence< OUString> aColNames(xColumns->getElementNames()); + + const OUString* pColBegin = aColNames.getConstArray(); + const OUString* pColEnd = pColBegin + aColNames.getLength(); + for(sal_Int32 j=1;pColBegin != pColEnd;++pColBegin,++j) + { + aRow[8] = new ORowSetValueDecorator(j); + aRow[9] = new ORowSetValueDecorator(*pColBegin); + aRows.push_back(aRow); + } + } + + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eIndexInfo); + Reference< XResultSet > xRef = pResult; + pResult->setRows(aRows); + return xRef; +} + +OUString SAL_CALL ODbaseDatabaseMetaData::getURL( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return "sdbc:dbase:" + m_pConnection->getURL(); +} + +sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return SAL_MAX_INT32; +} + +sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxCharLiteralLength( ) +{ + return 254; +} + +sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxColumnNameLength( ) +{ + return 10; +} + +sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxColumnsInIndex( ) +{ + return 1; +} + +sal_Int32 SAL_CALL ODbaseDatabaseMetaData::getMaxColumnsInTable( ) +{ + return 128; +} + +sal_Bool SAL_CALL ODbaseDatabaseMetaData::supportsAlterTableWithAddColumn( ) +{ + return true; +} + +sal_Bool SAL_CALL ODbaseDatabaseMetaData::supportsAlterTableWithDropColumn( ) +{ + return false; +} + +sal_Bool SAL_CALL ODbaseDatabaseMetaData::isReadOnly( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + bool bReadOnly = false; + ::ucbhelper::Content aFile(m_pConnection->getContent(),Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext()); + aFile.getPropertyValue("IsReadOnly") >>= bReadOnly; + + return bReadOnly; +} + +bool ODbaseDatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( ) +{ + return true; +} + +bool ODbaseDatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( ) +{ + return true; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DDriver.cxx b/connectivity/source/drivers/dbase/DDriver.cxx new file mode 100644 index 000000000..ab2d52413 --- /dev/null +++ b/connectivity/source/drivers/dbase/DDriver.cxx @@ -0,0 +1,119 @@ +/* -*- 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 <dbase/DDriver.hxx> +#include <dbase/DConnection.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> +#include <comphelper/processfactory.hxx> + +using namespace connectivity::dbase; +using namespace connectivity::file; +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::lang; + + +// static ServiceInfo + +OUString ODriver::getImplementationName_Static( ) +{ + return "com.sun.star.comp.sdbc.dbase.ODriver"; +} + + +OUString SAL_CALL ODriver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + + +css::uno::Reference< css::uno::XInterface > connectivity::dbase::ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory) +{ + return *(new ODriver( comphelper::getComponentContext(_rxFactory) )); +} + +Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url, const Sequence< PropertyValue >& info ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (ODriver_BASE::rBHelper.bDisposed) + throw DisposedException(); + + if ( ! acceptsURL(url) ) + return nullptr; + + ODbaseConnection* pCon = new ODbaseConnection(this); + pCon->construct(url,info); + Reference< XConnection > xCon = pCon; + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + + return xCon; +} + +sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url ) +{ + return url.startsWith("sdbc:dbase:"); +} + +Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) +{ + if ( acceptsURL(url) ) + { + Sequence< OUString > aBoolean(2); + aBoolean[0] = "0"; + aBoolean[1] = "1"; + + DriverPropertyInfo aDriverInfo[] = { + { + "CharSet" + ,"CharSet of the database." + ,false + ,OUString() + ,Sequence< OUString >() + }, + { + "ShowDeleted" + ,"Display inactive records." + ,false + ,"0" + ,aBoolean + }, + { + "EnableSQL92Check" + ,"Use SQL92 naming constraints." + ,false + ,"0" + ,aBoolean + } + }; + + return Sequence< DriverPropertyInfo >(aDriverInfo, std::size(aDriverInfo)); + } + + SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + return Sequence< DriverPropertyInfo >(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DIndex.cxx b/connectivity/source/drivers/dbase/DIndex.cxx new file mode 100644 index 000000000..d168de39e --- /dev/null +++ b/connectivity/source/drivers/dbase/DIndex.cxx @@ -0,0 +1,611 @@ +/* -*- 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 <dbase/DIndex.hxx> +#include <dbase/DIndexColumns.hxx> +#include <dbase/DTable.hxx> +#include <dbase/DIndexIter.hxx> +#include <osl/file.hxx> +#include <sal/log.hxx> +#include <tools/config.hxx> +#include <connectivity/CommonTools.hxx> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <unotools/ucbhelper.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <connectivity/dbexception.hxx> +#include <dbase/DResultSet.hxx> +#include <strings.hrc> +#include <unotools/sharedunocomponent.hxx> + +using namespace ::comphelper; + +using namespace connectivity; +using namespace utl; +using namespace ::cppu; +using namespace connectivity::file; +using namespace connectivity::sdbcx; +using namespace connectivity::dbase; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; + +IMPLEMENT_SERVICE_INFO(ODbaseIndex,"com.sun.star.sdbcx.driver.dbase.Index","com.sun.star.sdbcx.Index"); + +ODbaseIndex::ODbaseIndex(ODbaseTable* _pTable) + : OIndex(true/*_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()*/) + , m_nCurNode(NODE_NOTFOUND) + , m_nPageCount(0) + , m_nRootPage(0) + , m_pTable(_pTable) + , m_bUseCollector(false) +{ + construct(); +} + +ODbaseIndex::ODbaseIndex( ODbaseTable* _pTable, + const NDXHeader& _rHeader, + const OUString& _rName) + : OIndex(_rName, OUString(), _rHeader.db_unique, false, false, true) + , m_aHeader(_rHeader) + , m_nCurNode(NODE_NOTFOUND) + , m_nPageCount(0) + , m_nRootPage(0) + , m_pTable(_pTable) + , m_bUseCollector(false) +{ + construct(); +} + +ODbaseIndex::~ODbaseIndex() +{ + closeImpl(); +} + +void ODbaseIndex::refreshColumns() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::std::vector< OUString> aVector; + if(!isNew()) + { + OSL_ENSURE(m_pFileStream,"FileStream is not opened!"); + OSL_ENSURE(m_aHeader.db_name[0] != '\0',"Invalid name for the column!"); + aVector.push_back(OUString::createFromAscii(m_aHeader.db_name)); + } + + if(m_pColumns) + m_pColumns->reFill(aVector); + else + m_pColumns.reset(new ODbaseIndexColumns(this,m_aMutex,aVector)); +} + +Sequence< sal_Int8 > ODbaseIndex::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// XUnoTunnel + +sal_Int64 ODbaseIndex::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return (isUnoTunnelId<ODbaseIndex>(rId)) + ? reinterpret_cast< sal_Int64 >( this ) + : ODbaseIndex_BASE::getSomething(rId); +} + +ONDXPagePtr const & ODbaseIndex::getRoot() +{ + openIndexFile(); + if (!m_aRoot.Is()) + { + m_nRootPage = m_aHeader.db_rootpage; + m_nPageCount = m_aHeader.db_pagecount; + m_aRoot = CreatePage(m_nRootPage,nullptr,true); + } + return m_aRoot; +} + +void ODbaseIndex::openIndexFile() +{ + if(m_pFileStream) + return; + + OUString sFile = getCompletePath(); + if(UCBContentHelper::Exists(sFile)) + { + m_pFileStream = OFileTable::createStream_simpleError(sFile, StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE); + if (!m_pFileStream) + m_pFileStream = OFileTable::createStream_simpleError(sFile, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE); + if(m_pFileStream) + { + m_pFileStream->SetEndian(SvStreamEndian::LITTLE); + m_pFileStream->SetBufferSize(DINDEX_PAGE_SIZE); + (*m_pFileStream) >> *this; + } + } + if(!m_pFileStream) + { + const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_LOAD_FILE, + "$filename$", sFile + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } +} + +std::unique_ptr<OIndexIterator> ODbaseIndex::createIterator() +{ + openIndexFile(); + return std::make_unique<OIndexIterator>(this); +} + +bool ODbaseIndex::ConvertToKey(ONDXKey* rKey, sal_uInt32 nRec, const ORowSetValue& rValue) +{ + OSL_ENSURE(m_pFileStream,"FileStream is not opened!"); + // Search a specific value in Index + // If the Index is unique, the key doesn't matter + try + { + if (m_aHeader.db_keytype == 0) + { + *rKey = ONDXKey(rValue.getString(), nRec ); + } + else + { + if (rValue.isNull()) + *rKey = ONDXKey(rValue.getDouble(), DataType::DOUBLE, nRec ); + else + *rKey = ONDXKey(rValue.getDouble(), nRec ); + } + } + catch (Exception&) + { + OSL_ASSERT(false); + return false; + } + return true; +} + + +bool ODbaseIndex::Find(sal_uInt32 nRec, const ORowSetValue& rValue) +{ + openIndexFile(); + OSL_ENSURE(m_pFileStream,"FileStream is not opened!"); + // Search a specific value in Index + // If the Index is unique, the key doesn't matter + ONDXKey aKey; + return ConvertToKey(&aKey, nRec, rValue) && getRoot()->Find(aKey); +} + + +bool ODbaseIndex::Insert(sal_uInt32 nRec, const ORowSetValue& rValue) +{ + openIndexFile(); + OSL_ENSURE(m_pFileStream,"FileStream is not opened!"); + ONDXKey aKey; + + // Does the value already exist + // Use Find() always to determine the actual leaf + if (!ConvertToKey(&aKey, nRec, rValue) || (getRoot()->Find(aKey) && isUnique())) + return false; + + ONDXNode aNewNode(aKey); + + // insert in the current leaf + if (!m_aCurLeaf.Is()) + return false; + + bool bResult = m_aCurLeaf->Insert(aNewNode); + Release(bResult); + + return bResult; +} + + +bool ODbaseIndex::Update(sal_uInt32 nRec, const ORowSetValue& rOldValue, + const ORowSetValue& rNewValue) +{ + openIndexFile(); + OSL_ENSURE(m_pFileStream,"FileStream is not opened!"); + ONDXKey aKey; + if (!ConvertToKey(&aKey, nRec, rNewValue) || (isUnique() && getRoot()->Find(aKey))) + return false; + else + return Delete(nRec, rOldValue) && Insert(nRec,rNewValue); +} + + +bool ODbaseIndex::Delete(sal_uInt32 nRec, const ORowSetValue& rValue) +{ + openIndexFile(); + OSL_ENSURE(m_pFileStream,"FileStream is not opened!"); + // Does the value already exist + // Always use Find() to determine the actual leaf + ONDXKey aKey; + if (!ConvertToKey(&aKey, nRec, rValue) || !getRoot()->Find(aKey)) + return false; + + // insert in the current leaf + if (!m_aCurLeaf.Is()) + return false; +#if OSL_DEBUG_LEVEL > 1 + m_aRoot->PrintPage(); +#endif + + m_aCurLeaf->Delete(m_nCurNode); + return true; +} + +void ODbaseIndex::Collect(ONDXPage* pPage) +{ + if (pPage) + m_aCollector.push_back(pPage); +} + +void ODbaseIndex::Release(bool bSave) +{ + // Release the Index-resources + m_bUseCollector = false; + + if (m_aCurLeaf.Is()) + { + m_aCurLeaf->Release(bSave); + m_aCurLeaf.Clear(); + } + + // Release the root + if (m_aRoot.Is()) + { + m_aRoot->Release(bSave); + m_aRoot.Clear(); + } + // Release all references, before the FileStream will be closed + for (auto& i : m_aCollector) + i->QueryDelete(); + + m_aCollector.clear(); + + // Header modified? + if (bSave && (m_aHeader.db_rootpage != m_nRootPage || + m_aHeader.db_pagecount != m_nPageCount)) + { + m_aHeader.db_rootpage = m_nRootPage; + m_aHeader.db_pagecount = m_nPageCount; + WriteODbaseIndex( *m_pFileStream, *this ); + } + m_nRootPage = m_nPageCount = 0; + m_nCurNode = NODE_NOTFOUND; + + closeImpl(); +} + +void ODbaseIndex::closeImpl() +{ + m_pFileStream.reset(); +} + +ONDXPage* ODbaseIndex::CreatePage(sal_uInt32 nPagePos, ONDXPage* pParent, bool bLoad) +{ + OSL_ENSURE(m_pFileStream,"FileStream is not opened!"); + + ONDXPage* pPage; + if ( !m_aCollector.empty() ) + { + pPage = *(m_aCollector.rbegin()); + m_aCollector.pop_back(); + pPage->SetPagePos(nPagePos); + pPage->SetParent(pParent); + } + else + pPage = new ONDXPage(*this, nPagePos, pParent); + + if (bLoad) + (*m_pFileStream) >> *pPage; + + return pPage; +} + +void connectivity::dbase::ReadHeader( + SvStream & rStream, ODbaseIndex::NDXHeader & rHeader) +{ +#if !defined(NDEBUG) + sal_uInt64 const nOldPos(rStream.Tell()); +#endif + rStream.ReadUInt32(rHeader.db_rootpage); + rStream.ReadUInt32(rHeader.db_pagecount); + rStream.ReadBytes(&rHeader.db_free, 4); + rStream.ReadUInt16(rHeader.db_keylen); + rStream.ReadUInt16(rHeader.db_maxkeys); + rStream.ReadUInt16(rHeader.db_keytype); + rStream.ReadUInt16(rHeader.db_keyrec); + rStream.ReadBytes(&rHeader.db_free1, 3); + rStream.ReadUChar(rHeader.db_unique); + rStream.ReadBytes(&rHeader.db_name, 488); + assert(rStream.GetError() || rStream.Tell() == nOldPos + DINDEX_PAGE_SIZE); +} + +SvStream& connectivity::dbase::operator >> (SvStream &rStream, ODbaseIndex& rIndex) +{ + rStream.Seek(0); + ReadHeader(rStream, rIndex.m_aHeader); + + rIndex.m_nRootPage = rIndex.m_aHeader.db_rootpage; + rIndex.m_nPageCount = rIndex.m_aHeader.db_pagecount; + return rStream; +} + +SvStream& connectivity::dbase::WriteODbaseIndex(SvStream &rStream, ODbaseIndex& rIndex) +{ + rStream.Seek(0); + rStream.WriteUInt32(rIndex.m_aHeader.db_rootpage); + rStream.WriteUInt32(rIndex.m_aHeader.db_pagecount); + rStream.WriteBytes(&rIndex.m_aHeader.db_free, 4); + rStream.WriteUInt16(rIndex.m_aHeader.db_keylen); + rStream.WriteUInt16(rIndex.m_aHeader.db_maxkeys); + rStream.WriteUInt16(rIndex.m_aHeader.db_keytype); + rStream.WriteUInt16(rIndex.m_aHeader.db_keyrec); + rStream.WriteBytes(&rIndex.m_aHeader.db_free1, 3); + rStream.WriteUChar(rIndex.m_aHeader.db_unique); + rStream.WriteBytes(&rIndex.m_aHeader.db_name, 488); + assert(rStream.GetError() || rStream.Tell() == DINDEX_PAGE_SIZE); + SAL_WARN_IF(rStream.GetError(), "connectivity.dbase", "write error"); + return rStream; +} + +OUString ODbaseIndex::getCompletePath() const +{ + OUString sDir = m_pTable->getConnection()->getURL() + + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) + + m_Name + ".ndx"; + return sDir; +} + +void ODbaseIndex::createINFEntry() +{ + // synchronize inf-file + const OUString sEntry(m_Name + ".ndx"); + + OUString sCfgFile(m_pTable->getConnection()->getURL() + + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) + + m_pTable->getName() + + ".inf"); + + OUString sPhysicalPath; + osl::FileBase::getSystemPathFromFileURL(sCfgFile, sPhysicalPath); + + Config aInfFile(sPhysicalPath); + aInfFile.SetGroup(dBASE_III_GROUP); + + sal_uInt16 nSuffix = aInfFile.GetKeyCount(); + OString aNewEntry,aKeyName; + bool bCase = isCaseSensitive(); + while (aNewEntry.isEmpty()) + { + aNewEntry = OString("NDX"); + aNewEntry += OString::number(++nSuffix); + for (sal_uInt16 i = 0; i < aInfFile.GetKeyCount(); i++) + { + aKeyName = aInfFile.GetKeyName(i); + if (bCase ? aKeyName == aNewEntry : aKeyName.equalsIgnoreAsciiCase(aNewEntry)) + { + aNewEntry.clear(); + break; + } + } + } + aInfFile.WriteKey(aNewEntry, OUStringToOString(sEntry, m_pTable->getConnection()->getTextEncoding())); +} + +void ODbaseIndex::DropImpl() +{ + closeImpl(); + + OUString sPath = getCompletePath(); + if(UCBContentHelper::Exists(sPath)) + { + if(!UCBContentHelper::Kill(sPath)) + m_pTable->getConnection()->throwGenericSQLException(STR_COULD_NOT_DELETE_INDEX,*m_pTable); + } + + // synchronize inf-file + OUString sCfgFile = m_pTable->getConnection()->getURL() + + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) + + m_pTable->getName() + ".inf"; + + OUString sPhysicalPath; + OSL_VERIFY( osl::FileBase::getSystemPathFromFileURL(sCfgFile, sPhysicalPath) + == osl::FileBase::E_None ); + + Config aInfFile(sPhysicalPath); + aInfFile.SetGroup(dBASE_III_GROUP); + sal_uInt16 nKeyCnt = aInfFile.GetKeyCount(); + OString aKeyName; + OUString sEntry = m_Name + ".ndx"; + + // delete entries from the inf file + for (sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++) + { + // References the Key to an Index-file? + aKeyName = aInfFile.GetKeyName( nKey ); + if (aKeyName.startsWith("NDX")) + { + if(sEntry == OStringToOUString(aInfFile.ReadKey(aKeyName),m_pTable->getConnection()->getTextEncoding())) + { + aInfFile.DeleteKey(aKeyName); + break; + } + } + } +} + +void ODbaseIndex::impl_killFileAndthrowError_throw(const char* pErrorId, const OUString& _sFile) +{ + closeImpl(); + if(UCBContentHelper::Exists(_sFile)) + UCBContentHelper::Kill(_sFile); + m_pTable->getConnection()->throwGenericSQLException(pErrorId, *this); +} + +void ODbaseIndex::CreateImpl() +{ + // Create the Index + const OUString sFile = getCompletePath(); + if(UCBContentHelper::Exists(sFile)) + { + const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_CREATE_INDEX_NAME, + "$filename$", sFile + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + // Index comprises only one column + if (m_pColumns->getCount() > 1) + m_pTable->getConnection()->throwGenericSQLException(STR_ONL_ONE_COLUMN_PER_INDEX,*this); + + Reference<XFastPropertySet> xCol(m_pColumns->getByIndex(0),UNO_QUERY); + + // Is the column already indexed? + if ( !xCol.is() ) + ::dbtools::throwFunctionSequenceException(*this); + + // create the index file + m_pFileStream = OFileTable::createStream_simpleError(sFile,StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE | StreamMode::TRUNC); + if (!m_pFileStream) + { + const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_LOAD_FILE, + "$filename$", sFile + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + + m_pFileStream->SetEndian(SvStreamEndian::LITTLE); + m_pFileStream->SetBufferSize(DINDEX_PAGE_SIZE); + + // firstly the result must be sorted + utl::SharedUNOComponent<XStatement> xStmt; + utl::SharedUNOComponent<XResultSet> xSet; + OUString aName; + try + { + xStmt.set( m_pTable->getConnection()->createStatement(), UNO_SET_THROW); + + aName = getString(xCol->getFastPropertyValue(PROPERTY_ID_NAME)); + + const OUString aQuote(m_pTable->getConnection()->getMetaData()->getIdentifierQuoteString()); + OUString aStatement( "SELECT " + aQuote + aName + aQuote +" FROM " + aQuote + m_pTable->getName() + aQuote + " ORDER BY " + aQuote + aName + aQuote); + + xSet.set( xStmt->executeQuery(aStatement),UNO_SET_THROW ); + } + catch(const Exception& ) + { + impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile); + } + if (!xSet.is()) + { + impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile); + } + + // Set the header info + memset(&m_aHeader,0,sizeof(m_aHeader)); + sal_Int32 nType = 0; + ::rtl::Reference<OSQLColumns> aCols = m_pTable->getTableColumns(); + const Reference< XPropertySet > xTableCol(*find(aCols->begin(),aCols->end(),aName,::comphelper::UStringMixEqual(isCaseSensitive()))); + + xTableCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType; + + m_aHeader.db_keytype = (nType == DataType::VARCHAR || nType == DataType::CHAR) ? 0 : 1; + m_aHeader.db_keylen = (m_aHeader.db_keytype) ? 8 : static_cast<sal_uInt16>(getINT32(xTableCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))); + m_aHeader.db_keylen = (( m_aHeader.db_keylen - 1) / 4 + 1) * 4; + m_aHeader.db_maxkeys = (DINDEX_PAGE_SIZE - 4) / (8 + m_aHeader.db_keylen); + if ( m_aHeader.db_maxkeys < 3 ) + { + impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX_KEYSIZE,sFile); + } + + m_pFileStream->SetStreamSize(DINDEX_PAGE_SIZE); + + OString aCol(OUStringToOString(aName, m_pTable->getConnection()->getTextEncoding())); + strncpy(m_aHeader.db_name, aCol.getStr(), std::min<size_t>(sizeof(m_aHeader.db_name), aCol.getLength())); + m_aHeader.db_unique = m_IsUnique ? 1: 0; + m_aHeader.db_keyrec = m_aHeader.db_keylen + 8; + + // modifications of the header are detected by differences between + // the HeaderInfo and nRootPage or nPageCount respectively + m_nRootPage = 1; + m_nPageCount = 2; + + m_aCurLeaf = m_aRoot = CreatePage(m_nRootPage); + m_aRoot->SetModified(true); + + m_bUseCollector = true; + + sal_Int32 nRowsLeft = 0; + Reference<XRow> xRow(xSet,UNO_QUERY); + + if(xSet->last()) + { + Reference< XUnoTunnel> xTunnel(xSet, UNO_QUERY_THROW); + ODbaseResultSet* pDbaseRes = reinterpret_cast< ODbaseResultSet* >( xTunnel->getSomething(ODbaseResultSet::getUnoTunnelId()) ); + assert(pDbaseRes); //"No dbase resultset found? What's going on here! + nRowsLeft = xSet->getRow(); + + xSet->beforeFirst(); + ORowSetValue atmpValue; + ONDXKey aKey(atmpValue, nType, 0); + ONDXKey aInsertKey(atmpValue, nType, 0); + // Create the index structure + while (xSet->next()) + { + ORowSetValue aValue(m_aHeader.db_keytype ? ORowSetValue(xRow->getDouble(1)) : ORowSetValue(xRow->getString(1))); + // checking for duplicate entries + if (m_IsUnique && m_nCurNode != NODE_NOTFOUND) + { + aKey.setValue(aValue); + if (aKey == (*m_aCurLeaf)[m_nCurNode].GetKey()) + { + impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX_NOT_UNIQUE,sFile); + } + } + aInsertKey.setValue(aValue); + aInsertKey.setRecord(pDbaseRes->getCurrentFilePos()); + + ONDXNode aNewNode(aInsertKey); + if (!m_aCurLeaf->Insert(aNewNode, --nRowsLeft)) + break; + } + } + + if(nRowsLeft) + { + impl_killFileAndthrowError_throw(STR_COULD_NOT_CREATE_INDEX,sFile); + } + Release(); + createINFEntry(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DIndexColumns.cxx b/connectivity/source/drivers/dbase/DIndexColumns.cxx new file mode 100644 index 000000000..886c7273d --- /dev/null +++ b/connectivity/source/drivers/dbase/DIndexColumns.cxx @@ -0,0 +1,82 @@ +/* -*- 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 <dbase/DIndexColumns.hxx> +#include <dbase/DTable.hxx> +#include <sdbcx/VIndexColumn.hxx> +#include <comphelper/types.hxx> + +using namespace ::comphelper; + +using namespace connectivity::dbase; +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; + + +sdbcx::ObjectType ODbaseIndexColumns::createObject(const OUString& _rName) +{ + const ODbaseTable* pTable = m_pIndex->getTable(); + + const ::rtl::Reference<OSQLColumns>& aCols = pTable->getTableColumns(); + OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive())); + + Reference< XPropertySet > xCol; + if(aIter != aCols->end()) + xCol = *aIter; + + if(!xCol.is()) + return sdbcx::ObjectType(); + + sdbcx::ObjectType xRet = new sdbcx::OIndexColumn(true,_rName + ,getString(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))) + ,OUString() + ,getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))) + ,getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))) + ,getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))) + ,getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) + ,pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers() + ,getString(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))) + ,getString(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))) + ,getString(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)))); + + return xRet; +} + + +void ODbaseIndexColumns::impl_refresh() +{ + m_pIndex->refreshColumns(); +} + +Reference< XPropertySet > ODbaseIndexColumns::createDescriptor() +{ + return new sdbcx::OIndexColumn(m_pIndex->getTable()->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()); +} + +sdbcx::ObjectType ODbaseIndexColumns::appendObject( const OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor ) +{ + return cloneDescriptor( descriptor ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DIndexIter.cxx b/connectivity/source/drivers/dbase/DIndexIter.cxx new file mode 100644 index 000000000..62cc6601a --- /dev/null +++ b/connectivity/source/drivers/dbase/DIndexIter.cxx @@ -0,0 +1,302 @@ +/* -*- 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 <dbase/DIndexIter.hxx> +#include <com/sun/star/sdb/SQLFilterOperator.hpp> + +using namespace ::com::sun::star::sdb; +using namespace connectivity; +using namespace connectivity::dbase; +using namespace connectivity::file; + +// OIndexIterator + + +OIndexIterator::~OIndexIterator() +{ +} + + +sal_uInt32 OIndexIterator::First() +{ + return Find(true); +} + + +sal_uInt32 OIndexIterator::Next() +{ + return Find(false); +} + +sal_uInt32 OIndexIterator::Find(bool bFirst) +{ + sal_uInt32 nRes = NODE_NOTFOUND; + + if (bFirst) + { + m_aRoot = m_xIndex->getRoot(); + m_aCurLeaf.Clear(); + } + + if (!m_pOperator) + { + // Preparation, position on the smallest element + if (bFirst) + { + ONDXPage* pPage = m_aRoot; + while (pPage && !pPage->IsLeaf()) + pPage = pPage->GetChild(m_xIndex.get()); + + m_aCurLeaf = pPage; + m_nCurNode = NODE_NOTFOUND; + } + ONDXKey* pKey = GetNextKey(); + nRes = pKey ? pKey->GetRecord() : NODE_NOTFOUND; + } + else if (dynamic_cast<const OOp_ISNOTNULL *>(m_pOperator) != nullptr) + nRes = GetNotNull(bFirst); + else if (dynamic_cast<const OOp_ISNULL *>(m_pOperator) != nullptr) + nRes = GetNull(bFirst); + else if (dynamic_cast<const OOp_LIKE *>(m_pOperator) != nullptr) + nRes = GetLike(bFirst); + else if (dynamic_cast<const OOp_COMPARE *>(m_pOperator) != nullptr) + nRes = GetCompare(bFirst); + + return nRes; +} + + +ONDXKey* OIndexIterator::GetFirstKey(ONDXPage* pPage, const OOperand& rKey) +{ + // searches a given key + // Speciality: At the end of the algorithm + // the actual page and the position of the node which fulfil the + // '<='-condition are saved. this is considered for inserts. + // ONDXIndex* m_pIndex = GetNDXIndex(); + OOp_COMPARE aTempOp(SQLFilterOperator::GREATER); + sal_uInt16 i = 0; + + if (pPage->IsLeaf()) + { + // in the leaf the actual operation is run, otherwise temp. (>) + while (i < pPage->Count() && !m_pOperator->operate(&((*pPage)[i]).GetKey(),&rKey)) + i++; + } + else + while (i < pPage->Count() && !aTempOp.operate(&((*pPage)[i]).GetKey(),&rKey)) + i++; + + + ONDXKey* pFoundKey = nullptr; + if (!pPage->IsLeaf()) + { + // descend further + ONDXPagePtr aPage = (i==0) ? pPage->GetChild(m_xIndex.get()) + : ((*pPage)[i-1]).GetChild(m_xIndex.get(), pPage); + pFoundKey = aPage.Is() ? GetFirstKey(aPage, rKey) : nullptr; + } + else if (i == pPage->Count()) + { + pFoundKey = nullptr; + } + else + { + pFoundKey = &(*pPage)[i].GetKey(); + if (!m_pOperator->operate(pFoundKey,&rKey)) + pFoundKey = nullptr; + + m_aCurLeaf = pPage; + m_nCurNode = pFoundKey ? i : i - 1; + } + return pFoundKey; +} + + +sal_uInt32 OIndexIterator::GetCompare(bool bFirst) +{ + ONDXKey* pKey = nullptr; + sal_Int32 ePredicateType = dynamic_cast<file::OOp_COMPARE&>(*m_pOperator).getPredicateType(); + + if (bFirst) + { + // Preparation, position on the smallest element + ONDXPage* pPage = m_aRoot; + switch (ePredicateType) + { + case SQLFilterOperator::NOT_EQUAL: + case SQLFilterOperator::LESS: + case SQLFilterOperator::LESS_EQUAL: + while (pPage && !pPage->IsLeaf()) + pPage = pPage->GetChild(m_xIndex.get()); + + m_aCurLeaf = pPage; + m_nCurNode = NODE_NOTFOUND; + } + + + switch (ePredicateType) + { + case SQLFilterOperator::NOT_EQUAL: + while ( ( pKey = GetNextKey() ) != nullptr ) + if (m_pOperator->operate(pKey,m_pOperand)) + break; + break; + case SQLFilterOperator::LESS: + while ( ( pKey = GetNextKey() ) != nullptr ) + if (!pKey->getValue().isNull()) + break; + break; + case SQLFilterOperator::LESS_EQUAL: + while ( ( pKey = GetNextKey() ) != nullptr ) ; + break; + case SQLFilterOperator::GREATER_EQUAL: + case SQLFilterOperator::EQUAL: + pKey = GetFirstKey(m_aRoot,*m_pOperand); + break; + case SQLFilterOperator::GREATER: + pKey = GetFirstKey(m_aRoot,*m_pOperand); + if ( !pKey ) + while ( ( pKey = GetNextKey() ) != nullptr ) + if (m_pOperator->operate(pKey,m_pOperand)) + break; + } + } + else + { + switch (ePredicateType) + { + case SQLFilterOperator::NOT_EQUAL: + while ( ( pKey = GetNextKey() ) != nullptr ) + if (m_pOperator->operate(pKey,m_pOperand)) + break; + break; + case SQLFilterOperator::LESS: + case SQLFilterOperator::LESS_EQUAL: + case SQLFilterOperator::EQUAL: + pKey = GetNextKey(); + if ( pKey == nullptr || !m_pOperator->operate(pKey,m_pOperand)) + { + pKey = nullptr; + m_aCurLeaf.Clear(); + } + break; + case SQLFilterOperator::GREATER_EQUAL: + case SQLFilterOperator::GREATER: + pKey = GetNextKey(); + } + } + + return pKey ? pKey->GetRecord() : NODE_NOTFOUND; +} + + +sal_uInt32 OIndexIterator::GetLike(bool bFirst) +{ + if (bFirst) + { + ONDXPage* pPage = m_aRoot; + + while (pPage && !pPage->IsLeaf()) + pPage = pPage->GetChild(m_xIndex.get()); + + m_aCurLeaf = pPage; + m_nCurNode = NODE_NOTFOUND; + } + + ONDXKey* pKey; + while ( ( pKey = GetNextKey() ) != nullptr ) + if (m_pOperator->operate(pKey,m_pOperand)) + break; + return pKey ? pKey->GetRecord() : NODE_NOTFOUND; +} + + +sal_uInt32 OIndexIterator::GetNull(bool bFirst) +{ + if (bFirst) + { + ONDXPage* pPage = m_aRoot; + while (pPage && !pPage->IsLeaf()) + pPage = pPage->GetChild(m_xIndex.get()); + + m_aCurLeaf = pPage; + m_nCurNode = NODE_NOTFOUND; + } + + ONDXKey* pKey = GetNextKey(); + if ( pKey == nullptr || !pKey->getValue().isNull()) + { + pKey = nullptr; + m_aCurLeaf.Clear(); + } + return pKey ? pKey->GetRecord() : NODE_NOTFOUND; +} + + +sal_uInt32 OIndexIterator::GetNotNull(bool bFirst) +{ + ONDXKey* pKey; + if (bFirst) + { + // go through all NULL values first + for (sal_uInt32 nRec = GetNull(bFirst); + nRec != NODE_NOTFOUND; + nRec = GetNull(false)) + ; + pKey = m_aCurLeaf.Is() ? &(*m_aCurLeaf)[m_nCurNode].GetKey() : nullptr; + } + else + pKey = GetNextKey(); + + return pKey ? pKey->GetRecord() : NODE_NOTFOUND; +} + + +ONDXKey* OIndexIterator::GetNextKey() +{ + if (m_aCurLeaf.Is() && ((++m_nCurNode) >= m_aCurLeaf->Count())) + { + ONDXPage* pPage = m_aCurLeaf; + // search next page + while (pPage) + { + ONDXPage* pParentPage = pPage->GetParent(); + if (pParentPage) + { + sal_uInt16 nPos = pParentPage->Search(pPage); + if (nPos != pParentPage->Count() - 1) + { // page found + pPage = (*pParentPage)[nPos+1].GetChild(m_xIndex.get(),pParentPage); + break; + } + } + pPage = pParentPage; + } + + // now go on with leaf + while (pPage && !pPage->IsLeaf()) + pPage = pPage->GetChild(m_xIndex.get()); + + m_aCurLeaf = pPage; + m_nCurNode = 0; + } + return m_aCurLeaf.Is() ? &(*m_aCurLeaf)[m_nCurNode].GetKey() : nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DIndexes.cxx b/connectivity/source/drivers/dbase/DIndexes.cxx new file mode 100644 index 000000000..1ebce2612 --- /dev/null +++ b/connectivity/source/drivers/dbase/DIndexes.cxx @@ -0,0 +1,116 @@ +/* -*- 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 <dbase/DIndexes.hxx> +#include <dbase/DIndex.hxx> +#include <comphelper/servicehelper.hxx> +#include <connectivity/dbexception.hxx> +#include <unotools/ucbhelper.hxx> +#include <strings.hrc> + +using namespace ::comphelper; + +using namespace utl; +using namespace ::connectivity; +using namespace ::dbtools; +using namespace ::connectivity::dbase; +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; + +sdbcx::ObjectType ODbaseIndexes::createObject(const OUString& _rName) +{ + OUString sFile = m_pTable->getConnection()->getURL() + + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELIMITER) + + _rName + ".ndx"; + if ( !UCBContentHelper::Exists(sFile) ) + { + const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_LOAD_FILE, + "$filename$", sFile + ) ); + ::dbtools::throwGenericSQLException( sError, *m_pTable ); + } + + sdbcx::ObjectType xRet; + std::unique_ptr<SvStream> pFileStream = ::connectivity::file::OFileTable::createStream_simpleError(sFile, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE); + if(pFileStream) + { + pFileStream->SetEndian(SvStreamEndian::LITTLE); + pFileStream->SetBufferSize(DINDEX_PAGE_SIZE); + ODbaseIndex::NDXHeader aHeader; + + pFileStream->Seek(0); + ReadHeader(*pFileStream, aHeader); + pFileStream.reset(); + + ODbaseIndex* pIndex = new ODbaseIndex(m_pTable,aHeader,_rName); + xRet = pIndex; + pIndex->openIndexFile(); + } + else + { + const OUString sError( m_pTable->getConnection()->getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_LOAD_FILE, + "$filename$", sFile + ) ); + ::dbtools::throwGenericSQLException( sError, *m_pTable ); + } + return xRet; +} + +void ODbaseIndexes::impl_refresh( ) +{ + if(m_pTable) + m_pTable->refreshIndexes(); +} + +Reference< XPropertySet > ODbaseIndexes::createDescriptor() +{ + return new ODbaseIndex(m_pTable); +} + +// XAppend +sdbcx::ObjectType ODbaseIndexes::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + Reference<XUnoTunnel> xTunnel(descriptor,UNO_QUERY); + if(xTunnel.is()) + { + ODbaseIndex* pIndex = reinterpret_cast< ODbaseIndex* >( xTunnel->getSomething(ODbaseIndex::getUnoTunnelId()) ); + if(!pIndex) + throw SQLException(); + pIndex->CreateImpl(); + } + + return createObject( _rForName ); +} + +// XDrop +void ODbaseIndexes::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/) +{ + auto pIndex = comphelper::getUnoTunnelImplementation<ODbaseIndex>(getObject(_nPos)); + if ( pIndex ) + pIndex->DropImpl(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DPreparedStatement.cxx b/connectivity/source/drivers/dbase/DPreparedStatement.cxx new file mode 100644 index 000000000..60e7a6a7f --- /dev/null +++ b/connectivity/source/drivers/dbase/DPreparedStatement.cxx @@ -0,0 +1,34 @@ +/* -*- 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 <dbase/DPreparedStatement.hxx> +#include <dbase/DResultSet.hxx> + +using namespace connectivity::dbase; +using namespace connectivity::file; +using namespace com::sun::star::uno; + +OResultSet* ODbasePreparedStatement::createResultSet() +{ + return new ODbaseResultSet(this,m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(ODbasePreparedStatement,"com.sun.star.sdbc.driver.dbase.PreparedStatement","com.sun.star.sdbc.PreparedStatement"); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DResultSet.cxx b/connectivity/source/drivers/dbase/DResultSet.cxx new file mode 100644 index 000000000..f9395a359 --- /dev/null +++ b/connectivity/source/drivers/dbase/DResultSet.cxx @@ -0,0 +1,211 @@ +/* -*- 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 <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <dbase/DResultSet.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <dbase/DIndex.hxx> +#include <dbase/DIndexIter.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> + +using namespace ::comphelper; + +using namespace connectivity::dbase; +using namespace connectivity::file; +using namespace ::cppu; +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::sdbcx; + +ODbaseResultSet::ODbaseResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator) + : file::OResultSet(pStmt,_aSQLIterator) + ,m_bBookmarkable(true) +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), PROPERTY_ID_ISBOOKMARKABLE, PropertyAttribute::READONLY,&m_bBookmarkable, cppu::UnoType<bool>::get()); +} + +OUString SAL_CALL ODbaseResultSet::getImplementationName( ) +{ + return "com.sun.star.sdbcx.dbase.ResultSet"; +} + +Sequence< OUString > SAL_CALL ODbaseResultSet::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL ODbaseResultSet::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Any SAL_CALL ODbaseResultSet::queryInterface( const Type & rType ) +{ + Any aRet = ODbaseResultSet_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OResultSet::queryInterface(rType); +} + + Sequence< Type > SAL_CALL ODbaseResultSet::getTypes( ) +{ + return ::comphelper::concatSequences(OResultSet::getTypes(),ODbaseResultSet_BASE::getTypes()); +} + + +// XRowLocate +Any SAL_CALL ODbaseResultSet::getBookmark( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + OSL_ENSURE((m_bShowDeleted || !m_aRow->isDeleted()),"getBookmark called for deleted row"); + + return makeAny(static_cast<sal_Int32>((*m_aRow)[0]->getValue())); +} + +sal_Bool SAL_CALL ODbaseResultSet::moveToBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false; + + return m_pTable.is() && Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),true); +} + +sal_Bool SAL_CALL ODbaseResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + if(!m_pTable.is()) + return false; + + + Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),false); + + return relative(rows); +} + + +sal_Int32 SAL_CALL ODbaseResultSet::compareBookmarks( const Any& lhs, const Any& rhs ) +{ + sal_Int32 nFirst(0),nSecond(0),nResult(0); + if ( !( lhs >>= nFirst ) || !( rhs >>= nSecond ) ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_INVALID_BOOKMARK); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } // if ( !( lhs >>= nFirst ) || !( rhs >>= nSecond ) ) + + if(nFirst < nSecond) + nResult = CompareBookmark::LESS; + else if(nFirst > nSecond) + nResult = CompareBookmark::GREATER; + else + nResult = CompareBookmark::EQUAL; + + return nResult; +} + +sal_Bool SAL_CALL ODbaseResultSet::hasOrderedBookmarks( ) +{ + return true; +} + +sal_Int32 SAL_CALL ODbaseResultSet::hashBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return comphelper::getINT32(bookmark); +} + +// XDeleteRows +Sequence< sal_Int32 > SAL_CALL ODbaseResultSet::deleteRows( const Sequence< Any >& /*rows*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFeatureNotImplementedSQLException( "XDeleteRows::deleteRows", *this ); + return Sequence< sal_Int32 >(); +} + +bool ODbaseResultSet::fillIndexValues(const Reference< XColumnsSupplier> &_xIndex) +{ + auto pIndex = comphelper::getUnoTunnelImplementation<dbase::ODbaseIndex>(_xIndex); + if(pIndex) + { + std::unique_ptr<dbase::OIndexIterator> pIter = pIndex->createIterator(); + + if (pIter) + { + sal_uInt32 nRec = pIter->First(); + while (nRec != NODE_NOTFOUND) + { + m_pFileSet->push_back(nRec); + nRec = pIter->Next(); + } + m_pFileSet->setFrozen(); + return true; + } + } + return false; +} + +::cppu::IPropertyArrayHelper & ODbaseResultSet::getInfoHelper() +{ + return *ODbaseResultSet_BASE3::getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* ODbaseResultSet::createArrayHelper() const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +void SAL_CALL ODbaseResultSet::acquire() throw() +{ + ODbaseResultSet_BASE2::acquire(); +} + +void SAL_CALL ODbaseResultSet::release() throw() +{ + ODbaseResultSet_BASE2::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODbaseResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +sal_Int32 ODbaseResultSet::getCurrentFilePos() const +{ + return m_pTable->getFilePos(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DStatement.cxx b/connectivity/source/drivers/dbase/DStatement.cxx new file mode 100644 index 000000000..096878e3e --- /dev/null +++ b/connectivity/source/drivers/dbase/DStatement.cxx @@ -0,0 +1,35 @@ +/* -*- 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 <dbase/DStatement.hxx> +#include <dbase/DResultSet.hxx> + +using namespace connectivity::dbase; +using namespace connectivity::file; +using namespace com::sun::star::uno; + + +OResultSet* ODbaseStatement::createResultSet() +{ + return new ODbaseResultSet(this,m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(ODbaseStatement,"com.sun.star.sdbc.driver.dbase.Statement","com.sun.star.sdbc.Statement"); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DTable.cxx b/connectivity/source/drivers/dbase/DTable.cxx new file mode 100644 index 000000000..ff01f3b6b --- /dev/null +++ b/connectivity/source/drivers/dbase/DTable.cxx @@ -0,0 +1,2732 @@ +/* -*- 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 <dbase/DTable.hxx> +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <o3tl/safeint.hxx> +#include <svl/converter.hxx> +#include <dbase/DConnection.hxx> +#include <dbase/DColumns.hxx> +#include <tools/config.hxx> +#include <dbase/DIndex.hxx> +#include <dbase/DIndexes.hxx> +#include <comphelper/processfactory.hxx> +#include <rtl/math.hxx> +#include <ucbhelper/content.hxx> +#include <com/sun/star/ucb/ContentCreationException.hpp> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <comphelper/property.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/string.hxx> +#include <unotools/tempfile.hxx> +#include <unotools/ucbhelper.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/FValue.hxx> +#include <connectivity/dbconversion.hxx> +#include <connectivity/sdbcx/VColumn.hxx> +#include <strings.hrc> +#include <rtl/strbuf.hxx> +#include <sal/log.hxx> +#include <tools/date.hxx> + +#include <algorithm> +#include <cassert> +#include <memory> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace connectivity::dbase; +using namespace connectivity::file; +using namespace ::ucbhelper; +using namespace ::utl; +using namespace ::cppu; +using namespace ::dbtools; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +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 ::com::sun::star::i18n; + +// stored as the Field Descriptor terminator +#define FIELD_DESCRIPTOR_TERMINATOR 0x0D +#define DBF_EOL 0x1A + +namespace +{ +std::size_t lcl_getFileSize(SvStream& _rStream) +{ + std::size_t nFileSize = 0; + _rStream.Seek(STREAM_SEEK_TO_END); + _rStream.SeekRel(-1); + char cEOL; + _rStream.ReadChar( cEOL ); + nFileSize = _rStream.Tell(); + if ( cEOL == DBF_EOL ) + nFileSize -= 1; + return nFileSize; +} +/** + calculates the Julian date +*/ +void lcl_CalcJulDate(sal_Int32& _nJulianDate,sal_Int32& _nJulianTime, const css::util::DateTime& rDateTime) +{ + css::util::DateTime aDateTime = rDateTime; + // weird: months fix + if (aDateTime.Month > 12) + { + aDateTime.Month--; + sal_uInt16 delta = rDateTime.Month / 12; + aDateTime.Year += delta; + aDateTime.Month -= delta * 12; + aDateTime.Month++; + } + + _nJulianTime = ((aDateTime.Hours*3600000)+(aDateTime.Minutes*60000)+(aDateTime.Seconds*1000)+(aDateTime.NanoSeconds/1000000)); + /* conversion factors */ + sal_uInt16 iy0; + sal_uInt16 im0; + if ( aDateTime.Month <= 2 ) + { + iy0 = aDateTime.Year - 1; + im0 = aDateTime.Month + 12; + } + else + { + iy0 = aDateTime.Year; + im0 = aDateTime.Month; + } + sal_Int32 ia = iy0 / 100; + sal_Int32 ib = 2 - ia + (ia >> 2); + /* calculate julian date */ + if ( aDateTime.Year <= 0 ) + { + _nJulianDate = static_cast<sal_Int32>((365.25 * iy0) - 0.75) + + static_cast<sal_Int32>(30.6001 * (im0 + 1) ) + + aDateTime.Day + 1720994; + } // if ( rDateTime.Year <= 0 ) + else + { + _nJulianDate = static_cast<sal_Int32>(365.25 * iy0) + + static_cast<sal_Int32>(30.6001 * (im0 + 1)) + + aDateTime.Day + 1720994; + } + double JD = _nJulianDate + 0.5; + _nJulianDate = static_cast<sal_Int32>( JD + 0.5); + const double gyr = aDateTime.Year + (0.01 * aDateTime.Month) + (0.0001 * aDateTime.Day); + if ( gyr >= 1582.1015 ) /* on or after 15 October 1582 */ + _nJulianDate += ib; +} + +/** + calculates date time from the Julian Date +*/ +void lcl_CalDate(sal_Int32 _nJulianDate,sal_Int32 _nJulianTime,css::util::DateTime& _rDateTime) +{ + if ( _nJulianDate ) + { + sal_Int32 ialp; + sal_Int32 ka = _nJulianDate; + if ( _nJulianDate >= 2299161 ) + { + ialp = static_cast<sal_Int32>( (static_cast<double>(_nJulianDate) - 1867216.25 ) / 36524.25 ); + ka = _nJulianDate + 1 + ialp - ( ialp >> 2 ); + } + sal_Int32 kb = ka + 1524; + sal_Int32 kc = static_cast<sal_Int32>( (static_cast<double>(kb) - 122.1 ) / 365.25 ); + sal_Int32 kd = static_cast<sal_Int32>(static_cast<double>(kc) * 365.25); + sal_Int32 ke = static_cast<sal_Int32>(static_cast<double>( kb - kd ) / 30.6001 ); + _rDateTime.Day = static_cast<sal_uInt16>(kb - kd - static_cast<sal_Int32>( static_cast<double>(ke) * 30.6001 )); + if ( ke > 13 ) + _rDateTime.Month = static_cast<sal_uInt16>(ke - 13); + else + _rDateTime.Month = static_cast<sal_uInt16>(ke - 1); + if ( (_rDateTime.Month == 2) && (_rDateTime.Day > 28) ) + _rDateTime.Day = 29; + if ( (_rDateTime.Month == 2) && (_rDateTime.Day == 29) && (ke == 3) ) + _rDateTime.Year = static_cast<sal_uInt16>(kc - 4716); + else if ( _rDateTime.Month > 2 ) + _rDateTime.Year = static_cast<sal_uInt16>(kc - 4716); + else + _rDateTime.Year = static_cast<sal_uInt16>(kc - 4715); + } + + if ( _nJulianTime ) + { + double d_s = _nJulianTime / 1000.0; + double d_m = d_s / 60.0; + double d_h = d_m / 60.0; + _rDateTime.Hours = static_cast<sal_uInt16>(d_h); + _rDateTime.Minutes = static_cast<sal_uInt16>((d_h - static_cast<double>(_rDateTime.Hours)) * 60.0); + _rDateTime.Seconds = static_cast<sal_uInt16>(((d_m - static_cast<double>(_rDateTime.Minutes)) * 60.0) + - (static_cast<double>(_rDateTime.Hours) * 3600.0)); + } +} + +} + + +void ODbaseTable::readHeader() +{ + OSL_ENSURE(m_pFileStream,"No Stream available!"); + if(!m_pFileStream) + return; + m_pFileStream->RefreshBuffer(); // Make sure, that the header information actually is read again + m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN); + + sal_uInt8 nType=0; + m_pFileStream->ReadUChar( nType ); + if(ERRCODE_NONE != m_pFileStream->GetErrorCode()) + throwInvalidDbaseFormat(); + + m_pFileStream->ReadBytes(m_aHeader.dateElems, 3); + if(ERRCODE_NONE != m_pFileStream->GetErrorCode()) + throwInvalidDbaseFormat(); + + m_pFileStream->ReadUInt32( m_aHeader.nbRecords); + if(ERRCODE_NONE != m_pFileStream->GetErrorCode()) + throwInvalidDbaseFormat(); + + m_pFileStream->ReadUInt16( m_aHeader.headerLength); + if(ERRCODE_NONE != m_pFileStream->GetErrorCode()) + throwInvalidDbaseFormat(); + + m_pFileStream->ReadUInt16( m_aHeader.recordLength); + if(ERRCODE_NONE != m_pFileStream->GetErrorCode()) + throwInvalidDbaseFormat(); + if (m_aHeader.recordLength == 0) + throwInvalidDbaseFormat(); + + m_pFileStream->ReadBytes(m_aHeader.trailer, 20); + if(ERRCODE_NONE != m_pFileStream->GetErrorCode()) + throwInvalidDbaseFormat(); + + + if ( ( ( m_aHeader.headerLength - 1 ) / 32 - 1 ) <= 0 ) // number of fields + { + // no dBASE file + throwInvalidDbaseFormat(); + } + else + { + // Consistency check of the header: + m_aHeader.type = static_cast<DBFType>(nType); + switch (m_aHeader.type) + { + case dBaseIII: + case dBaseIV: + case dBaseV: + case VisualFoxPro: + case VisualFoxProAuto: + case dBaseFS: + case dBaseFSMemo: + case dBaseIVMemoSQL: + case dBaseIIIMemo: + case FoxProMemo: + m_pFileStream->SetEndian(SvStreamEndian::LITTLE); + if( getConnection()->isTextEncodingDefaulted() && + !dbfDecodeCharset(m_eEncoding, nType, m_aHeader.trailer[17])) + { + m_eEncoding = RTL_TEXTENCODING_IBM_850; + } + break; + case dBaseIVMemo: + m_pFileStream->SetEndian(SvStreamEndian::LITTLE); + break; + default: + { + throwInvalidDbaseFormat(); + } + } + } +} + +void ODbaseTable::fillColumns() +{ + m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN); + m_pFileStream->Seek(32); + + if(!m_aColumns.is()) + m_aColumns = new OSQLColumns(); + else + m_aColumns->clear(); + + m_aTypes.clear(); + m_aPrecisions.clear(); + m_aScales.clear(); + + // Number of fields: + const sal_Int32 nFieldCount = (m_aHeader.headerLength - 1) / 32 - 1; + OSL_ENSURE(nFieldCount,"No columns in table!"); + + m_aColumns->reserve(nFieldCount); + m_aTypes.reserve(nFieldCount); + m_aPrecisions.reserve(nFieldCount); + m_aScales.reserve(nFieldCount); + + OUString aTypeName; + const bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(); + const bool bFoxPro = m_aHeader.type == VisualFoxPro || m_aHeader.type == VisualFoxProAuto || m_aHeader.type == FoxProMemo; + + sal_Int32 i = 0; + for (; i < nFieldCount; i++) + { + DBFColumn aDBFColumn; +#if !defined(NDEBUG) + sal_uInt64 const nOldPos(m_pFileStream->Tell()); +#endif + m_pFileStream->ReadBytes(aDBFColumn.db_fnm, 11); + m_pFileStream->ReadUChar(aDBFColumn.db_typ); + m_pFileStream->ReadUInt32(aDBFColumn.db_adr); + m_pFileStream->ReadUChar(aDBFColumn.db_flng); + m_pFileStream->ReadUChar(aDBFColumn.db_dez); + m_pFileStream->ReadBytes(aDBFColumn.db_free2, 14); + assert(m_pFileStream->GetError() || m_pFileStream->Tell() == nOldPos + sizeof(aDBFColumn)); + if (m_pFileStream->GetError()) + { + SAL_WARN("connectivity.drivers", "ODbaseTable::fillColumns: short read!"); + break; + } + if ( FIELD_DESCRIPTOR_TERMINATOR == aDBFColumn.db_fnm[0] ) // 0x0D stored as the Field Descriptor terminator. + break; + + aDBFColumn.db_fnm[sizeof(aDBFColumn.db_fnm)-1] = 0; //ensure null termination for broken input + const OUString aColumnName(reinterpret_cast<char *>(aDBFColumn.db_fnm), strlen(reinterpret_cast<char *>(aDBFColumn.db_fnm)), m_eEncoding); + + bool bIsRowVersion = bFoxPro && ( aDBFColumn.db_free2[0] & 0x01 ) == 0x01; + + m_aRealFieldLengths.push_back(aDBFColumn.db_flng); + sal_Int32 nPrecision = aDBFColumn.db_flng; + sal_Int32 eType; + bool bIsCurrency = false; + + char cType[2]; + cType[0] = aDBFColumn.db_typ; + cType[1] = 0; + aTypeName = OUString(cType, 1, RTL_TEXTENCODING_ASCII_US); + SAL_INFO( "connectivity.drivers","column type: " << aDBFColumn.db_typ); + + switch (aDBFColumn.db_typ) + { + case 'C': + eType = DataType::VARCHAR; + aTypeName = "VARCHAR"; + break; + case 'F': + case 'N': + aTypeName = "DECIMAL"; + if ( aDBFColumn.db_typ == 'N' ) + aTypeName = "NUMERIC"; + eType = DataType::DECIMAL; + + // for numeric fields two characters more are written, then the precision of the column description predescribes, + // to keep room for the possible sign and the comma. This has to be considered... + nPrecision = SvDbaseConverter::ConvertPrecisionToOdbc(nPrecision,aDBFColumn.db_dez); + // This is not true for older versions... + break; + case 'L': + eType = DataType::BIT; + aTypeName = "BOOLEAN"; + break; + case 'Y': + bIsCurrency = true; + eType = DataType::DOUBLE; + aTypeName = "DOUBLE"; + break; + case 'D': + eType = DataType::DATE; + aTypeName = "DATE"; + break; + case 'T': + eType = DataType::TIMESTAMP; + aTypeName = "TIMESTAMP"; + break; + case 'I': + eType = DataType::INTEGER; + aTypeName = "INTEGER"; + break; + case 'M': + if ( bFoxPro && ( aDBFColumn.db_free2[0] & 0x04 ) == 0x04 ) + { + eType = DataType::LONGVARBINARY; + aTypeName = "LONGVARBINARY"; + } + else + { + aTypeName = "LONGVARCHAR"; + eType = DataType::LONGVARCHAR; + } + nPrecision = 2147483647; + break; + case 'P': + aTypeName = "LONGVARBINARY"; + eType = DataType::LONGVARBINARY; + nPrecision = 2147483647; + break; + case '0': + case 'B': + if ( m_aHeader.type == VisualFoxPro || m_aHeader.type == VisualFoxProAuto ) + { + aTypeName = "DOUBLE"; + eType = DataType::DOUBLE; + } + else + { + aTypeName = "LONGVARBINARY"; + eType = DataType::LONGVARBINARY; + nPrecision = 2147483647; + } + break; + default: + eType = DataType::OTHER; + } + + m_aTypes.push_back(eType); + m_aPrecisions.push_back(nPrecision); + m_aScales.push_back(aDBFColumn.db_dez); + + Reference< XPropertySet> xCol = new sdbcx::OColumn(aColumnName, + aTypeName, + OUString(), + OUString(), + ColumnValue::NULLABLE, + nPrecision, + aDBFColumn.db_dez, + eType, + false, + bIsRowVersion, + bIsCurrency, + bCase, + m_CatalogName, getSchema(), getName()); + m_aColumns->push_back(xCol); + } // for (; i < nFieldCount; i++) + OSL_ENSURE(i,"No columns in table!"); +} + +ODbaseTable::ODbaseTable(sdbcx::OCollection* _pTables, ODbaseConnection* _pConnection) + : ODbaseTable_BASE(_pTables,_pConnection) +{ + // initialize the header + m_aHeader.type = dBaseIII; + m_eEncoding = getConnection()->getTextEncoding(); +} + +ODbaseTable::ODbaseTable(sdbcx::OCollection* _pTables, ODbaseConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName ) + : ODbaseTable_BASE(_pTables,_pConnection,Name, + Type, + Description, + SchemaName, + CatalogName) +{ + m_eEncoding = getConnection()->getTextEncoding(); +} + + +void ODbaseTable::construct() +{ + // initialize the header + m_aHeader.type = dBaseIII; + m_aHeader.nbRecords = 0; + m_aHeader.headerLength = 0; + m_aHeader.recordLength = 0; + m_aMemoHeader.db_size = 0; + + OUString sFileName(getEntry(m_pConnection, m_Name)); + + INetURLObject aURL; + aURL.SetURL(sFileName); + + OSL_ENSURE( m_pConnection->matchesExtension( aURL.getExtension() ), + "ODbaseTable::ODbaseTable: invalid extension!"); + // getEntry is expected to ensure the correct file name + + m_pFileStream = createStream_simpleError( sFileName, StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE); + m_bWriteable = ( m_pFileStream != nullptr ); + + if ( !m_pFileStream ) + { + m_bWriteable = false; + m_pFileStream = createStream_simpleError( sFileName, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE); + } + + if(!m_pFileStream) + return; + + readHeader(); + if (HasMemoFields()) + { + // Create Memo-Filename (.DBT): + // nyi: Ugly for Unix and Mac! + + if ( m_aHeader.type == FoxProMemo || m_aHeader.type == VisualFoxPro || m_aHeader.type == VisualFoxProAuto) // foxpro uses another extension + aURL.SetExtension("fpt"); + else + aURL.SetExtension("dbt"); + + // If the memo file isn't found, the data will be displayed anyhow. + // However, updates can't be done + // but the operation is executed + m_pMemoStream = createStream_simpleError( aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE); + if ( !m_pMemoStream ) + { + m_pMemoStream = createStream_simpleError( aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE); + } + if (m_pMemoStream) + ReadMemoHeader(); + } + fillColumns(); + + std::size_t nFileSize = lcl_getFileSize(*m_pFileStream); + m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN); + // seems to be empty or someone wrote bullshit into the dbase file + // try and recover if m_aHeader.db_slng is sane + if (m_aHeader.nbRecords == 0 && m_aHeader.recordLength) + { + std::size_t nRecords = (nFileSize-m_aHeader.headerLength)/m_aHeader.recordLength; + if (nRecords > 0) + m_aHeader.nbRecords = nRecords; + } + + // Buffersize dependent on the file size + m_pFileStream->SetBufferSize(nFileSize > 1000000 ? 32768 : + nFileSize > 100000 ? 16384 : + nFileSize > 10000 ? 4096 : 1024); + + if (m_pMemoStream) + { + // set the buffer exactly to the length of a record + nFileSize = m_pMemoStream->TellEnd(); + m_pMemoStream->Seek(STREAM_SEEK_TO_BEGIN); + + // Buffersize dependent on the file size + m_pMemoStream->SetBufferSize(nFileSize > 1000000 ? 32768 : + nFileSize > 100000 ? 16384 : + nFileSize > 10000 ? 4096 : + m_aMemoHeader.db_size); + } + + AllocBuffer(); +} + +void ODbaseTable::ReadMemoHeader() +{ + m_pMemoStream->SetEndian(SvStreamEndian::LITTLE); + m_pMemoStream->RefreshBuffer(); // make sure that the header information is actually read again + m_pMemoStream->Seek(0); + + (*m_pMemoStream).ReadUInt32( m_aMemoHeader.db_next ); + switch (m_aHeader.type) + { + case dBaseIIIMemo: // dBase III: fixed block size + case dBaseIVMemo: + // sometimes dBase3 is attached to dBase4 memo + m_pMemoStream->Seek(20); + (*m_pMemoStream).ReadUInt16( m_aMemoHeader.db_size ); + if (m_aMemoHeader.db_size > 1 && m_aMemoHeader.db_size != 512) // 1 is also for dBase 3 + m_aMemoHeader.db_typ = MemodBaseIV; + else if (m_aMemoHeader.db_size == 512) + { + // There are files using size specification, though they are dBase-files + char sHeader[4]; + m_pMemoStream->Seek(m_aMemoHeader.db_size); + m_pMemoStream->ReadBytes(sHeader, 4); + + if ((m_pMemoStream->GetErrorCode() != ERRCODE_NONE) || static_cast<sal_uInt8>(sHeader[0]) != 0xFF || static_cast<sal_uInt8>(sHeader[1]) != 0xFF || static_cast<sal_uInt8>(sHeader[2]) != 0x08) + m_aMemoHeader.db_typ = MemodBaseIII; + else + m_aMemoHeader.db_typ = MemodBaseIV; + } + else + { + m_aMemoHeader.db_typ = MemodBaseIII; + m_aMemoHeader.db_size = 512; + } + break; + case VisualFoxPro: + case VisualFoxProAuto: + case FoxProMemo: + m_aMemoHeader.db_typ = MemoFoxPro; + m_pMemoStream->Seek(6); + m_pMemoStream->SetEndian(SvStreamEndian::BIG); + (*m_pMemoStream).ReadUInt16( m_aMemoHeader.db_size ); + break; + default: + SAL_WARN( "connectivity.drivers", "ODbaseTable::ReadMemoHeader: unsupported memo type!" ); + break; + } +} + +OUString ODbaseTable::getEntry(file::OConnection const * _pConnection,const OUString& _sName ) +{ + OUString sURL; + try + { + Reference< XResultSet > xDir = _pConnection->getDir()->getStaticResultSet(); + Reference< XRow> xRow(xDir,UNO_QUERY); + OUString sName; + OUString sExt; + INetURLObject aURL; + xDir->beforeFirst(); + while(xDir->next()) + { + sName = xRow->getString(1); + aURL.SetSmartProtocol(INetProtocol::File); + OUString sUrl = _pConnection->getURL() + "/" + sName; + aURL.SetSmartURL( sUrl ); + + // cut the extension + sExt = aURL.getExtension(); + + // name and extension have to coincide + if ( _pConnection->matchesExtension( sExt ) ) + { + sName = sName.replaceAt(sName.getLength() - (sExt.getLength() + 1), sExt.getLength() + 1, OUString()); + if ( sName == _sName ) + { + Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY ); + sURL = xContentAccess->queryContentIdentifierString(); + break; + } + } + } + xDir->beforeFirst(); // move back to before first record + } + catch(const Exception&) + { + OSL_ASSERT(false); + } + return sURL; +} + +void ODbaseTable::refreshColumns() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::std::vector< OUString> aVector; + aVector.reserve(m_aColumns->size()); + + for (auto const& column : *m_aColumns) + aVector.push_back(Reference< XNamed>(column,UNO_QUERY_THROW)->getName()); + + if(m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns = new ODbaseColumns(this,m_aMutex,aVector); +} + +void ODbaseTable::refreshIndexes() +{ + ::std::vector< OUString> aVector; + if(m_pFileStream && (!m_xIndexes || m_xIndexes->getCount() == 0)) + { + INetURLObject aURL; + aURL.SetURL(getEntry(m_pConnection,m_Name)); + + aURL.setExtension("inf"); + Config aInfFile(aURL.getFSysPath(FSysStyle::Detect)); + aInfFile.SetGroup(dBASE_III_GROUP); + sal_uInt16 nKeyCnt = aInfFile.GetKeyCount(); + OString aKeyName; + + for (sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++) + { + // References the key an index-file? + aKeyName = aInfFile.GetKeyName( nKey ); + //...if yes, add the index list of the table + if (aKeyName.startsWith("NDX")) + { + OString aIndexName = aInfFile.ReadKey(aKeyName); + aURL.setName(OStringToOUString(aIndexName, m_eEncoding)); + try + { + Content aCnt(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext()); + if (aCnt.isDocument()) + { + aVector.push_back(aURL.getBase()); + } + } + catch(const Exception&) // an exception is thrown when no file exists + { + } + } + } + } + if(m_xIndexes) + m_xIndexes->reFill(aVector); + else + m_xIndexes = new ODbaseIndexes(this,m_aMutex,aVector); +} + + +void SAL_CALL ODbaseTable::disposing() +{ + OFileTable::disposing(); + ::osl::MutexGuard aGuard(m_aMutex); + m_aColumns = nullptr; +} + +Sequence< Type > SAL_CALL ODbaseTable::getTypes( ) +{ + Sequence< Type > aTypes = OTable_TYPEDEF::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!(*pBegin == cppu::UnoType<XKeysSupplier>::get()|| + *pBegin == cppu::UnoType<XDataDescriptorFactory>::get())) + { + aOwnTypes.push_back(*pBegin); + } + } + aOwnTypes.push_back(cppu::UnoType<css::lang::XUnoTunnel>::get()); + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +Any SAL_CALL ODbaseTable::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType<XKeysSupplier>::get()|| + rType == cppu::UnoType<XDataDescriptorFactory>::get()) + return Any(); + + Any aRet = OTable_TYPEDEF::queryInterface(rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< css::lang::XUnoTunnel*> (this)); +} + + +Sequence< sal_Int8 > ODbaseTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 ODbaseTable::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return (isUnoTunnelId<ODbaseTable>(rId)) + ? reinterpret_cast< sal_Int64 >( this ) + : ODbaseTable_BASE::getSomething(rId); +} + +bool ODbaseTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns & _rCols, bool bRetrieveData) +{ + if (!m_pBuffer) + return false; + + // Read the data + bool bIsCurRecordDeleted = static_cast<char>(m_pBuffer[0]) == '*'; + + // only read the bookmark + + // Mark record as deleted + _rRow->setDeleted(bIsCurRecordDeleted); + *(*_rRow)[0] = m_nFilePos; + + if (!bRetrieveData) + return true; + + std::size_t nByteOffset = 1; + // Fields: + OSQLColumns::const_iterator aIter = _rCols.begin(); + OSQLColumns::const_iterator aEnd = _rCols.end(); + const std::size_t nCount = _rRow->size(); + for (std::size_t i = 1; aIter != aEnd && nByteOffset <= m_nBufferSize && i < nCount;++aIter, i++) + { + // Lengths depending on data type: + sal_Int32 nLen = 0; + sal_Int32 nType = 0; + nLen = m_aPrecisions[i-1]; + nType = m_aTypes[i-1]; + + switch(nType) + { + case DataType::INTEGER: + case DataType::DOUBLE: + case DataType::TIMESTAMP: + case DataType::DATE: + case DataType::BIT: + case DataType::LONGVARCHAR: + case DataType::LONGVARBINARY: + nLen = m_aRealFieldLengths[i-1]; + break; + case DataType::DECIMAL: + nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,m_aScales[i-1]); + break; // the sign and the comma + + case DataType::BINARY: + case DataType::OTHER: + nByteOffset += nLen; + continue; + } + + // Is the variable bound? + if ( !(*_rRow)[i]->isBound() ) + { + // No - next field. + nByteOffset += nLen; + OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!"); + continue; + } // if ( !(_rRow->get())[i]->isBound() ) + if ( ( nByteOffset + nLen) > m_nBufferSize ) + break; // length doesn't match buffer size. + + char *pData = reinterpret_cast<char *>(m_pBuffer.get() + nByteOffset); + + if (nType == DataType::CHAR || nType == DataType::VARCHAR) + { + sal_Int32 nLastPos = -1; + for (sal_Int32 k = 0; k < nLen; ++k) + { + if (pData[k] != ' ') + // Record last non-empty position. + nLastPos = k; + } + if (nLastPos < 0) + { + // Empty string. Skip it. + (*_rRow)[i]->setNull(); + } + else + { + // Commit the string. Use intern() to ref-count it. + *(*_rRow)[i] = OUString::intern(pData, static_cast<sal_Int32>(nLastPos+1), m_eEncoding); + } + } // if (nType == DataType::CHAR || nType == DataType::VARCHAR) + else if ( DataType::TIMESTAMP == nType ) + { + sal_Int32 nDate = 0,nTime = 0; + memcpy(&nDate, pData, 4); + memcpy(&nTime, pData+ 4, 4); + if ( !nDate && !nTime ) + { + (*_rRow)[i]->setNull(); + } + else + { + css::util::DateTime aDateTime; + lcl_CalDate(nDate,nTime,aDateTime); + *(*_rRow)[i] = aDateTime; + } + } + else if ( DataType::INTEGER == nType ) + { + sal_Int32 nValue = 0; + if (o3tl::make_unsigned(nLen) > sizeof(nValue)) + return false; + memcpy(&nValue, pData, nLen); + *(*_rRow)[i] = nValue; + } + else if ( DataType::DOUBLE == nType ) + { + double d = 0.0; + if (getBOOL((*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency is treated separately + { + sal_Int64 nValue = 0; + if (o3tl::make_unsigned(nLen) > sizeof(nValue)) + return false; + memcpy(&nValue, pData, nLen); + + if ( m_aScales[i-1] ) + d = (nValue / pow(10.0,static_cast<int>(m_aScales[i-1]))); + else + d = static_cast<double>(nValue); + } + else + { + if (o3tl::make_unsigned(nLen) > sizeof(d)) + return false; + memcpy(&d, pData, nLen); + } + + *(*_rRow)[i] = d; + } + else + { + sal_Int32 nPos1 = -1, nPos2 = -1; + // If the string contains Nul-characters, then convert them to blanks! + for (sal_Int32 k = 0; k < nLen; k++) + { + if (pData[k] == '\0') + pData[k] = ' '; + + if (pData[k] != ' ') + { + if (nPos1 < 0) + // first non-empty char position. + nPos1 = k; + + // last non-empty char position. + nPos2 = k; + } + } + + if (nPos1 < 0) + { + // Empty string. Skip it. + nByteOffset += nLen; + (*_rRow)[i]->setNull(); // no values -> done + continue; + } + + OUString aStr = OUString::intern(pData+nPos1, nPos2-nPos1+1, m_eEncoding); + + switch (nType) + { + case DataType::DATE: + { + if (aStr.getLength() != nLen) + { + (*_rRow)[i]->setNull(); + break; + } + const sal_uInt16 nYear = static_cast<sal_uInt16>(aStr.copy( 0, 4 ).toInt32()); + const sal_uInt16 nMonth = static_cast<sal_uInt16>(aStr.copy( 4, 2 ).toInt32()); + const sal_uInt16 nDay = static_cast<sal_uInt16>(aStr.copy( 6, 2 ).toInt32()); + + const css::util::Date aDate(nDay,nMonth,nYear); + *(*_rRow)[i] = aDate; + } + break; + case DataType::DECIMAL: + *(*_rRow)[i] = ORowSetValue(aStr); + break; + case DataType::BIT: + { + bool b; + switch (*pData) + { + case 'T': + case 'Y': + case 'J': b = true; break; + default: b = false; break; + } + *(*_rRow)[i] = b; + } + break; + case DataType::LONGVARBINARY: + case DataType::BINARY: + case DataType::LONGVARCHAR: + { + const long nBlockNo = aStr.toInt32(); // read blocknumber + if (nBlockNo > 0 && m_pMemoStream) // Read data from memo-file, only if + { + if ( !ReadMemo(nBlockNo, (*_rRow)[i]->get()) ) + break; + } + else + (*_rRow)[i]->setNull(); + } break; + default: + SAL_WARN( "connectivity.drivers","Wrong type"); + } + (*_rRow)[i]->setTypeKind(nType); + } + + nByteOffset += nLen; + OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!"); + } + return true; +} + + +void ODbaseTable::FileClose() +{ + ::osl::MutexGuard aGuard(m_aMutex); + // if not everything has been written yet + if (m_pMemoStream && m_pMemoStream->IsWritable()) + m_pMemoStream->Flush(); + + m_pMemoStream.reset(); + + ODbaseTable_BASE::FileClose(); +} + +bool ODbaseTable::CreateImpl() +{ + OSL_ENSURE(!m_pFileStream, "SequenceError"); + + if ( m_pConnection->isCheckEnabled() && ::dbtools::convertName2SQLName(m_Name,OUString()) != m_Name ) + { + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_SQL_NAME_ERROR, + "$name$", m_Name + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + OUString aName = getEntry(m_pConnection, m_Name); + if(aName.isEmpty()) + { + OUString aIdent = m_pConnection->getContent()->getIdentifier()->getContentIdentifier(); + if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) ) + aIdent += "/"; + aIdent += m_Name; + aName = aIdent; + } + aURL.SetURL(aName); + + if ( !m_pConnection->matchesExtension( aURL.getExtension() ) ) + aURL.setExtension(m_pConnection->getExtension()); + + try + { + Content aContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext()); + if (aContent.isDocument()) + { + // Only if the file exists with length > 0 raise an error + std::unique_ptr<SvStream> pFileStream(createStream_simpleError( aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::READ)); + + if (pFileStream && pFileStream->TellEnd()) + return false; + } + } + catch(const Exception&) // an exception is thrown when no file exists + { + } + + bool bMemoFile = false; + + bool bOk = CreateFile(aURL, bMemoFile); + + FileClose(); + + if (!bOk) + { + try + { + Content aContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext()); + aContent.executeCommand( "delete", css::uno::Any( true ) ); + } + catch(const Exception&) // an exception is thrown when no file exists + { + } + return false; + } + + if (bMemoFile) + { + OUString aExt = aURL.getExtension(); + aURL.setExtension("dbt"); // extension for memo file + + bool bMemoAlreadyExists = false; + try + { + Content aMemo1Content(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext()); + bMemoAlreadyExists = aMemo1Content.isDocument(); + } + catch(const Exception&) // an exception is thrown when no file exists + { + } + if (bMemoAlreadyExists) + { + aURL.setExtension(aExt); // kill dbf file + try + { + Content aMemoContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext()); + aMemoContent.executeCommand( "delete", css::uno::Any( true ) ); + } + catch(const Exception&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_DELETE_FILE, + "$name$", aName + ) ); + ::dbtools::throwGenericSQLException( sError, *this, anyEx ); + } + } + if (!CreateMemoFile(aURL)) + { + aURL.setExtension(aExt); // kill dbf file + try + { + Content aMemoContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext()); + aMemoContent.executeCommand( "delete", css::uno::Any( true ) ); + } + catch(const ContentCreationException&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_DELETE_FILE, + "$name$", aName + ) ); + ::dbtools::throwGenericSQLException( sError, *this, anyEx ); + } + return false; + } + m_aHeader.type = dBaseIIIMemo; + } + else + m_aHeader.type = dBaseIII; + + return true; +} + +void ODbaseTable::throwInvalidColumnType(const char* pErrorId, const OUString& _sColumnName) +{ + try + { + // we have to drop the file because it is corrupted now + DropImpl(); + } + catch(const Exception&) + { + } + + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + pErrorId, + "$columnname$", _sColumnName + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); +} + +// creates in principle dBase IV file format +bool ODbaseTable::CreateFile(const INetURLObject& aFile, bool& bCreateMemo) +{ + bCreateMemo = false; + Date aDate( Date::SYSTEM ); // current date + + m_pFileStream = createStream_simpleError( aFile.GetMainURL(INetURLObject::DecodeMechanism::NONE),StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE | StreamMode::TRUNC ); + + if (!m_pFileStream) + return false; + + sal_uInt8 nDbaseType = dBaseIII; + Reference<XIndexAccess> xColumns(getColumns(),UNO_QUERY); + Reference<XPropertySet> xCol; + const OUString sPropType = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE); + + try + { + const sal_Int32 nCount = xColumns->getCount(); + for(sal_Int32 i=0;i<nCount;++i) + { + xColumns->getByIndex(i) >>= xCol; + OSL_ENSURE(xCol.is(),"This should be a column!"); + + switch (getINT32(xCol->getPropertyValue(sPropType))) + { + case DataType::DOUBLE: + case DataType::INTEGER: + case DataType::TIMESTAMP: + case DataType::LONGVARBINARY: + nDbaseType = VisualFoxPro; + i = nCount; // no more columns need to be checked + break; + } // switch (getINT32(xCol->getPropertyValue(sPropType))) + } + } + catch ( const Exception& ) + { + try + { + // we have to drop the file because it is corrupted now + DropImpl(); + } + catch(const Exception&) { } + throw; + } + + char aBuffer[21] = {}; // write buffer + + m_pFileStream->Seek(0); + (*m_pFileStream).WriteUChar( nDbaseType ); // dBase format + (*m_pFileStream).WriteUChar( aDate.GetYearUnsigned() % 100 ); // current date + + + (*m_pFileStream).WriteUChar( aDate.GetMonth() ); + (*m_pFileStream).WriteUChar( aDate.GetDay() ); + (*m_pFileStream).WriteUInt32( 0 ); // number of data records + (*m_pFileStream).WriteUInt16( (m_xColumns->getCount()+1) * 32 + 1 ); // header information, + // pColumns contains always an additional column + (*m_pFileStream).WriteUInt16( 0 ); // record length will be determined later + m_pFileStream->WriteBytes(aBuffer, 20); + + sal_uInt16 nRecLength = 1; // Length 1 for deleted flag + sal_Int32 nMaxFieldLength = m_pConnection->getMetaData()->getMaxColumnNameLength(); + OUString aName; + const OUString sPropName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME); + const OUString sPropPrec = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION); + const OUString sPropScale = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE); + + try + { + const sal_Int32 nCount = xColumns->getCount(); + for(sal_Int32 i=0;i<nCount;++i) + { + xColumns->getByIndex(i) >>= xCol; + OSL_ENSURE(xCol.is(),"This should be a column!"); + + char cTyp( 'C' ); + + xCol->getPropertyValue(sPropName) >>= aName; + + OString aCol; + if ( DBTypeConversion::convertUnicodeString( aName, aCol, m_eEncoding ) > nMaxFieldLength) + { + throwInvalidColumnType( STR_INVALID_COLUMN_NAME_LENGTH, aName ); + } + + m_pFileStream->WriteOString( aCol ); + m_pFileStream->WriteBytes(aBuffer, 11 - aCol.getLength()); + + sal_Int32 nPrecision = 0; + xCol->getPropertyValue(sPropPrec) >>= nPrecision; + sal_Int32 nScale = 0; + xCol->getPropertyValue(sPropScale) >>= nScale; + + bool bBinary = false; + + switch (getINT32(xCol->getPropertyValue(sPropType))) + { + case DataType::CHAR: + case DataType::VARCHAR: + cTyp = 'C'; + break; + case DataType::DOUBLE: + if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency will be treated separately + cTyp = 'Y'; + else + cTyp = 'B'; + break; + case DataType::INTEGER: + cTyp = 'I'; + break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::BIGINT: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::REAL: + cTyp = 'N'; // only dBase 3 format + break; + case DataType::TIMESTAMP: + cTyp = 'T'; + break; + case DataType::DATE: + cTyp = 'D'; + break; + case DataType::BIT: + cTyp = 'L'; + break; + case DataType::LONGVARBINARY: + bBinary = true; + [[fallthrough]]; + case DataType::LONGVARCHAR: + cTyp = 'M'; + break; + default: + { + throwInvalidColumnType(STR_INVALID_COLUMN_TYPE, aName); + } + } + + (*m_pFileStream).WriteChar( cTyp ); + if ( nDbaseType == VisualFoxPro ) + (*m_pFileStream).WriteUInt32( nRecLength-1 ); + else + m_pFileStream->WriteBytes(aBuffer, 4); + + switch(cTyp) + { + case 'C': + OSL_ENSURE(nPrecision < 255, "ODbaseTable::Create: Column too long!"); + if (nPrecision > 254) + { + throwInvalidColumnType(STR_INVALID_COLUMN_PRECISION, aName); + } + (*m_pFileStream).WriteUChar( std::min(static_cast<unsigned>(nPrecision), 255U) ); // field length + nRecLength = nRecLength + static_cast<sal_uInt16>(std::min(static_cast<sal_uInt16>(nPrecision), sal_uInt16(255UL))); + (*m_pFileStream).WriteUChar( 0 ); // decimals + break; + case 'F': + case 'N': + OSL_ENSURE(nPrecision >= nScale, + "ODbaseTable::Create: Field length must be larger than decimal places!"); + if (nPrecision < nScale) + { + throwInvalidColumnType(STR_INVALID_PRECISION_SCALE, aName); + } + if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency will be treated separately + { + (*m_pFileStream).WriteUChar( 10 ); // standard length + (*m_pFileStream).WriteUChar( 4 ); + nRecLength += 10; + } + else + { + sal_Int32 nPrec = SvDbaseConverter::ConvertPrecisionToDbase(nPrecision,nScale); + + (*m_pFileStream).WriteUChar( nPrec ); + (*m_pFileStream).WriteUChar( nScale ); + nRecLength += static_cast<sal_uInt16>(nPrec); + } + break; + case 'L': + (*m_pFileStream).WriteUChar( 1 ); + (*m_pFileStream).WriteUChar( 0 ); + ++nRecLength; + break; + case 'I': + (*m_pFileStream).WriteUChar( 4 ); + (*m_pFileStream).WriteUChar( 0 ); + nRecLength += 4; + break; + case 'Y': + case 'B': + case 'T': + case 'D': + (*m_pFileStream).WriteUChar( 8 ); + (*m_pFileStream).WriteUChar( 0 ); + nRecLength += 8; + break; + case 'M': + bCreateMemo = true; + (*m_pFileStream).WriteUChar( 10 ); + (*m_pFileStream).WriteUChar( 0 ); + nRecLength += 10; + if ( bBinary ) + aBuffer[0] = 0x06; + break; + default: + throwInvalidColumnType(STR_INVALID_COLUMN_TYPE, aName); + } + m_pFileStream->WriteBytes(aBuffer, 14); + aBuffer[0] = 0x00; + } + + (*m_pFileStream).WriteUChar( FIELD_DESCRIPTOR_TERMINATOR ); // end of header + (*m_pFileStream).WriteChar( char(DBF_EOL) ); + m_pFileStream->Seek(10); + (*m_pFileStream).WriteUInt16( nRecLength ); // set record length afterwards + + if (bCreateMemo) + { + m_pFileStream->Seek(0); + if (nDbaseType == VisualFoxPro) + (*m_pFileStream).WriteUChar( FoxProMemo ); + else + (*m_pFileStream).WriteUChar( dBaseIIIMemo ); + } // if (bCreateMemo) + } + catch ( const Exception& ) + { + try + { + // we have to drop the file because it is corrupted now + DropImpl(); + } + catch(const Exception&) { } + throw; + } + return true; +} + + +// creates in principle dBase III file format +bool ODbaseTable::CreateMemoFile(const INetURLObject& aFile) +{ + // filehandling macro for table creation + m_pMemoStream = createStream_simpleError( aFile.GetMainURL(INetURLObject::DecodeMechanism::NONE),StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE); + + if (!m_pMemoStream) + return false; + + m_pMemoStream->SetStreamSize(512); + + m_pMemoStream->Seek(0); + (*m_pMemoStream).WriteUInt32( 1 ); // pointer to the first free block + + m_pMemoStream->Flush(); + m_pMemoStream.reset(); + return true; +} + +bool ODbaseTable::Drop_Static(const OUString& _sUrl, bool _bHasMemoFields, OCollection* _pIndexes ) +{ + INetURLObject aURL; + aURL.SetURL(_sUrl); + + bool bDropped = ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + + if(bDropped) + { + if (_bHasMemoFields) + { // delete the memo fields + aURL.setExtension("dbt"); + bDropped = ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + } + + if(bDropped) + { + if(_pIndexes) + { + try + { + sal_Int32 i = _pIndexes->getCount(); + while (i) + { + _pIndexes->dropByIndex(--i); + } + } + catch(const SQLException&) + { + } + } + aURL.setExtension("inf"); + + // as the inf file does not necessarily exist, we aren't allowed to use UCBContentHelper::Kill + try + { + ::ucbhelper::Content aDeleteContent( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + aDeleteContent.executeCommand( "delete", makeAny( true ) ); + } + catch(const Exception&) + { + // silently ignore this... + } + } + } + return bDropped; +} + +bool ODbaseTable::DropImpl() +{ + FileClose(); + + if(!m_xIndexes) + refreshIndexes(); // look for indexes which must be deleted as well + + bool bDropped = Drop_Static(getEntry(m_pConnection,m_Name),HasMemoFields(),m_xIndexes.get()); + if(!bDropped) + {// we couldn't drop the table so we have to reopen it + construct(); + if(m_xColumns) + m_xColumns->refresh(); + } + return bDropped; +} + + +bool ODbaseTable::InsertRow(OValueRefVector& rRow, const Reference<XIndexAccess>& _xCols) +{ + // fill buffer with blanks + if (!AllocBuffer()) + return false; + + memset(m_pBuffer.get(), 0, m_aHeader.recordLength); + m_pBuffer[0] = ' '; + + // Copy new row completely: + // ... and add at the end as new Record: + std::size_t nTempPos = m_nFilePos; + + m_nFilePos = static_cast<std::size_t>(m_aHeader.nbRecords) + 1; + bool bInsertRow = UpdateBuffer( rRow, nullptr, _xCols, true ); + if ( bInsertRow ) + { + std::size_t nFileSize = 0, nMemoFileSize = 0; + + nFileSize = lcl_getFileSize(*m_pFileStream); + + if (HasMemoFields() && m_pMemoStream) + { + m_pMemoStream->Seek(STREAM_SEEK_TO_END); + nMemoFileSize = m_pMemoStream->Tell(); + } + + if (!WriteBuffer()) + { + m_pFileStream->SetStreamSize(nFileSize); // restore old size + + if (HasMemoFields() && m_pMemoStream) + m_pMemoStream->SetStreamSize(nMemoFileSize); // restore old size + m_nFilePos = nTempPos; // restore file position + } + else + { + (*m_pFileStream).WriteChar( char(DBF_EOL) ); // write EOL + // raise number of datasets in the header: + m_pFileStream->Seek( 4 ); + (*m_pFileStream).WriteUInt32( m_aHeader.nbRecords + 1 ); + + m_pFileStream->Flush(); + + // raise number if successfully + m_aHeader.nbRecords++; + *rRow[0] = m_nFilePos; // set bookmark + m_nFilePos = nTempPos; + } + } + else + m_nFilePos = nTempPos; + + return bInsertRow; +} + + +bool ODbaseTable::UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow, const Reference<XIndexAccess>& _xCols) +{ + // fill buffer with blanks + if (!AllocBuffer()) + return false; + + // position on desired record: + std::size_t nPos = m_aHeader.headerLength + static_cast<long>(m_nFilePos-1) * m_aHeader.recordLength; + m_pFileStream->Seek(nPos); + m_pFileStream->ReadBytes(m_pBuffer.get(), m_aHeader.recordLength); + + std::size_t nMemoFileSize( 0 ); + if (HasMemoFields() && m_pMemoStream) + { + m_pMemoStream->Seek(STREAM_SEEK_TO_END); + nMemoFileSize = m_pMemoStream->Tell(); + } + if (!UpdateBuffer(rRow, pOrgRow, _xCols, false) || !WriteBuffer()) + { + if (HasMemoFields() && m_pMemoStream) + m_pMemoStream->SetStreamSize(nMemoFileSize); // restore old size + } + else + { + m_pFileStream->Flush(); + } + return true; +} + + +bool ODbaseTable::DeleteRow(const OSQLColumns& _rCols) +{ + // Set the Delete-Flag (be it set or not): + // Position on desired record: + std::size_t nFilePos = m_aHeader.headerLength + static_cast<long>(m_nFilePos-1) * m_aHeader.recordLength; + m_pFileStream->Seek(nFilePos); + + OValueRefRow aRow = new OValueRefVector(_rCols.size()); + + if (!fetchRow(aRow,_rCols,true)) + return false; + + Reference<XPropertySet> xCol; + OUString aColName; + ::comphelper::UStringMixEqual aCase(isCaseSensitive()); + for (sal_Int32 i = 0; i < m_xColumns->getCount(); i++) + { + Reference<XPropertySet> xIndex = isUniqueByColumnName(i); + if (xIndex.is()) + { + xCol.set(m_xColumns->getByIndex(i), css::uno::UNO_QUERY); + OSL_ENSURE(xCol.is(),"ODbaseTable::DeleteRow column is null!"); + if(xCol.is()) + { + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName; + + Reference<XUnoTunnel> xTunnel(xIndex,UNO_QUERY); + OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!"); + ODbaseIndex* pIndex = reinterpret_cast< ODbaseIndex* >( xTunnel->getSomething(ODbaseIndex::getUnoTunnelId()) ); + OSL_ENSURE(pIndex,"ODbaseTable::DeleteRow: No Index returned!"); + + OSQLColumns::const_iterator aIter = std::find_if(_rCols.begin(), _rCols.end(), + [&aCase, &aColName](const OSQLColumns::value_type& rxCol) { + return aCase(getString(rxCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME))), aColName); }); + if (aIter == _rCols.end()) + continue; + + auto nPos = static_cast<sal_Int32>(std::distance(_rCols.begin(), aIter)) + 1; + pIndex->Delete(m_nFilePos,*(*aRow)[nPos]); + } + } + } + + m_pFileStream->Seek(nFilePos); + (*m_pFileStream).WriteUChar( '*' ); // mark the row in the table as deleted + m_pFileStream->Flush(); + return true; +} + +Reference<XPropertySet> ODbaseTable::isUniqueByColumnName(sal_Int32 _nColumnPos) +{ + if(!m_xIndexes) + refreshIndexes(); + if(m_xIndexes->hasElements()) + { + Reference<XPropertySet> xCol; + m_xColumns->getByIndex(_nColumnPos) >>= xCol; + OSL_ENSURE(xCol.is(),"ODbaseTable::isUniqueByColumnName column is null!"); + OUString sColName; + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sColName; + + Reference<XPropertySet> xIndex; + for(sal_Int32 i=0;i<m_xIndexes->getCount();++i) + { + xIndex.set(m_xIndexes->getByIndex(i), css::uno::UNO_QUERY); + if(xIndex.is() && getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE)))) + { + Reference<XNameAccess> xCols(Reference<XColumnsSupplier>(xIndex,UNO_QUERY_THROW)->getColumns()); + if(xCols->hasByName(sColName)) + return xIndex; + + } + } + } + return Reference<XPropertySet>(); +} + +static double toDouble(const OString& rString) +{ + return ::rtl::math::stringToDouble( rString, '.', ',' ); +} + + +bool ODbaseTable::UpdateBuffer(OValueRefVector& rRow, const OValueRefRow& pOrgRow, const Reference<XIndexAccess>& _xCols, const bool bForceAllFields) +{ + OSL_ENSURE(m_pBuffer,"Buffer is NULL!"); + if ( !m_pBuffer ) + return false; + sal_Int32 nByteOffset = 1; + + // Update fields: + Reference<XPropertySet> xCol; + Reference<XPropertySet> xIndex; + OUString aColName; + const sal_Int32 nColumnCount = m_xColumns->getCount(); + std::vector< Reference<XPropertySet> > aIndexedCols(nColumnCount); + + ::comphelper::UStringMixEqual aCase(isCaseSensitive()); + + Reference<XIndexAccess> xColumns = m_xColumns.get(); + // first search a key that exist already in the table + for (sal_Int32 i = 0; i < nColumnCount; ++i) + { + sal_Int32 nPos = i; + if(_xCols != xColumns) + { + m_xColumns->getByIndex(i) >>= xCol; + OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!"); + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName; + + for(nPos = 0;nPos<_xCols->getCount();++nPos) + { + Reference<XPropertySet> xFindCol( + _xCols->getByIndex(nPos), css::uno::UNO_QUERY); + OSL_ENSURE(xFindCol.is(),"ODbaseTable::UpdateBuffer column is null!"); + if(aCase(getString(xFindCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),aColName)) + break; + } + if (nPos >= _xCols->getCount()) + continue; + } + + ++nPos; + xIndex = isUniqueByColumnName(i); + aIndexedCols[i] = xIndex; + if (xIndex.is()) + { + // first check if the value is different to the old one and when if it conform to the index + if(pOrgRow.is() && (rRow[nPos]->getValue().isNull() || rRow[nPos] == (*pOrgRow)[nPos])) + continue; + else + { + Reference<XUnoTunnel> xTunnel(xIndex,UNO_QUERY); + OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!"); + ODbaseIndex* pIndex = reinterpret_cast< ODbaseIndex* >( xTunnel->getSomething(ODbaseIndex::getUnoTunnelId()) ); + OSL_ENSURE(pIndex,"ODbaseTable::UpdateBuffer: No Index returned!"); + + if (pIndex->Find(0,*rRow[nPos])) + { + // There is no unique value + if ( aColName.isEmpty() ) + { + m_xColumns->getByIndex(i) >>= xCol; + OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!"); + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName; + xCol.clear(); + } // if ( !aColName.getLength() ) + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_DUPLICATE_VALUE_IN_COLUMN + ,"$columnname$", aColName + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + } + } + } + + // when we are here there is no double key in the table + + for (sal_Int32 i = 0; i < nColumnCount && nByteOffset <= m_nBufferSize ; ++i) + { + // Lengths for each data type: + assert(i >= 0); + OSL_ENSURE(o3tl::make_unsigned(i) < m_aPrecisions.size(),"Illegal index!"); + sal_Int32 nLen = 0; + sal_Int32 nType = 0; + sal_Int32 nScale = 0; + if ( o3tl::make_unsigned(i) < m_aPrecisions.size() ) + { + nLen = m_aPrecisions[i]; + nType = m_aTypes[i]; + nScale = m_aScales[i]; + } + else + { + m_xColumns->getByIndex(i) >>= xCol; + if ( xCol.is() ) + { + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nLen; + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType; + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale; + } + } + + bool bSetZero = false; + switch (nType) + { + case DataType::INTEGER: + case DataType::DOUBLE: + case DataType::TIMESTAMP: + bSetZero = true; + [[fallthrough]]; + case DataType::LONGVARBINARY: + case DataType::DATE: + case DataType::BIT: + case DataType::LONGVARCHAR: + nLen = m_aRealFieldLengths[i]; + break; + case DataType::DECIMAL: + nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,nScale); + break; // The sign and the comma + default: + break; + + } // switch (nType) + + sal_Int32 nPos = i; + if(_xCols != xColumns) + { + m_xColumns->getByIndex(i) >>= xCol; + OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!"); + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName; + for(nPos = 0;nPos<_xCols->getCount();++nPos) + { + Reference<XPropertySet> xFindCol( + _xCols->getByIndex(nPos), css::uno::UNO_QUERY); + if(aCase(getString(xFindCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),aColName)) + break; + } + if (nPos >= _xCols->getCount()) + { + nByteOffset += nLen; + continue; + } + } + + + ++nPos; // the row values start at 1 + const ORowSetValue &thisColVal = rRow[nPos]->get(); + const bool thisColIsBound = thisColVal.isBound(); + const bool thisColIsNull = !thisColIsBound || thisColVal.isNull(); + // don't overwrite non-bound columns + if ( ! (bForceAllFields || thisColIsBound) ) + { + // No - don't overwrite this field, it has not changed. + nByteOffset += nLen; + continue; + } + if (aIndexedCols[i].is()) + { + Reference<XUnoTunnel> xTunnel(aIndexedCols[i],UNO_QUERY); + OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!"); + ODbaseIndex* pIndex = reinterpret_cast< ODbaseIndex* >( xTunnel->getSomething(ODbaseIndex::getUnoTunnelId()) ); + OSL_ENSURE(pIndex,"ODbaseTable::UpdateBuffer: No Index returned!"); + // Update !! + if (pOrgRow.is() && !thisColIsNull) + pIndex->Update(m_nFilePos, *(*pOrgRow)[nPos], thisColVal); + else + pIndex->Insert(m_nFilePos, thisColVal); + } + + char* pData = reinterpret_cast<char *>(m_pBuffer.get() + nByteOffset); + if (thisColIsNull) + { + if ( bSetZero ) + memset(pData,0,nLen); // Clear to NULL char ('\0') + else + memset(pData,' ',nLen); // Clear to space/blank ('\0x20') + nByteOffset += nLen; + OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!"); + continue; + } + + try + { + switch (nType) + { + case DataType::TIMESTAMP: + { + sal_Int32 nJulianDate = 0, nJulianTime = 0; + lcl_CalcJulDate(nJulianDate,nJulianTime, thisColVal); + // Exactly 8 bytes to copy: + memcpy(pData,&nJulianDate,4); + memcpy(pData+4,&nJulianTime,4); + } + break; + case DataType::DATE: + { + css::util::Date aDate; + if(thisColVal.getTypeKind() == DataType::DOUBLE) + aDate = ::dbtools::DBTypeConversion::toDate(thisColVal.getDouble()); + else + aDate = thisColVal; + char s[sizeof("-327686553565535")]; + // reserve enough space for hypothetical max length + snprintf(s, + sizeof(s), + "%04" SAL_PRIdINT32 "%02" SAL_PRIuUINT32 "%02" SAL_PRIuUINT32, + static_cast<sal_Int32>(aDate.Year), + static_cast<sal_uInt32>(aDate.Month), + static_cast<sal_uInt32>(aDate.Day)); + + // Exactly 8 bytes to copy (even if s could hypothetically be longer): + memcpy(pData,s,8); + } break; + case DataType::INTEGER: + { + sal_Int32 nValue = thisColVal; + if (o3tl::make_unsigned(nLen) > sizeof(nValue)) + return false; + memcpy(pData,&nValue,nLen); + } + break; + case DataType::DOUBLE: + { + const double d = thisColVal; + m_xColumns->getByIndex(i) >>= xCol; + + if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency is treated separately + { + sal_Int64 nValue = 0; + if ( m_aScales[i] ) + nValue = static_cast<sal_Int64>(d * pow(10.0,static_cast<int>(m_aScales[i]))); + else + nValue = static_cast<sal_Int64>(d); + if (o3tl::make_unsigned(nLen) > sizeof(nValue)) + return false; + memcpy(pData,&nValue,nLen); + } // if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency is treated separately + else + { + if (o3tl::make_unsigned(nLen) > sizeof(d)) + return false; + memcpy(pData,&d,nLen); + } + } + break; + case DataType::DECIMAL: + { + memset(pData,' ',nLen); // Clear to NULL + + const double n = thisColVal; + + // one, because const_cast GetFormatPrecision on SvNumberFormat is not constant, + // even though it really could and should be + const OString aDefaultValue( ::rtl::math::doubleToString( n, rtl_math_StringFormat_F, nScale, '.', nullptr, 0)); + const sal_Int32 nValueLen = aDefaultValue.getLength(); + if ( nValueLen <= nLen ) + { + // Write value right-justified, padded with blanks to the left. + memcpy(pData+nLen-nValueLen,aDefaultValue.getStr(),nValueLen); + // write the resulting double back + *rRow[nPos] = toDouble(aDefaultValue); + } + else + { + m_xColumns->getByIndex(i) >>= xCol; + OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!"); + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName; + std::vector< std::pair<const char* , OUString > > aStringToSubstitutes; + aStringToSubstitutes.push_back(std::pair<const char* , OUString >("$columnname$", aColName)); + aStringToSubstitutes.push_back(std::pair<const char* , OUString >("$precision$", OUString::number(nLen))); + aStringToSubstitutes.push_back(std::pair<const char* , OUString >("$scale$", OUString::number(nScale))); + aStringToSubstitutes.push_back(std::pair<const char* , OUString >("$value$", OStringToOUString(aDefaultValue,RTL_TEXTENCODING_UTF8))); + + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_INVALID_COLUMN_DECIMAL_VALUE + ,aStringToSubstitutes + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + } break; + case DataType::BIT: + *pData = thisColVal.getBool() ? 'T' : 'F'; + break; + case DataType::LONGVARBINARY: + case DataType::LONGVARCHAR: + { + char cNext = pData[nLen]; // Mark's scratch and replaced by 0 + pData[nLen] = '\0'; // This is because the buffer is always a sign of greater ... + + std::size_t nBlockNo = strtol(pData,nullptr,10); // Block number read + + // Next initial character restore again: + pData[nLen] = cNext; + if (!m_pMemoStream) + break; + WriteMemo(thisColVal, nBlockNo); + + OString aBlock(OString::number(nBlockNo)); + //align aBlock at the right of a nLen sequence, fill to the left with '0' + OStringBuffer aStr; + comphelper::string::padToLength(aStr, nLen - aBlock.getLength(), '0'); + aStr.append(aBlock); + + // Copy characters: + memcpy(pData, aStr.getStr(), nLen); + } break; + default: + { + memset(pData,' ',nLen); // Clear to NULL + + OUString sStringToWrite( thisColVal.getString() ); + + // convert the string, using the connection's encoding + OString sEncoded; + + DBTypeConversion::convertUnicodeStringToLength( sStringToWrite, sEncoded, nLen, m_eEncoding ); + memcpy( pData, sEncoded.getStr(), sEncoded.getLength() ); + + } + break; + } + } + catch( const SQLException& ) + { + throw; + } + catch ( const Exception& ) + { + m_xColumns->getByIndex(i) >>= xCol; + OSL_ENSURE( xCol.is(), "ODbaseTable::UpdateBuffer column is null!" ); + if ( xCol.is() ) + xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName; + + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_INVALID_COLUMN_VALUE, + "$columnname$", aColName + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + // And more ... + nByteOffset += nLen; + OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!"); + } + return true; +} + + +void ODbaseTable::WriteMemo(const ORowSetValue& aVariable, std::size_t& rBlockNr) +{ + // if the BlockNo 0 is given, the block will be appended at the end + std::size_t nSize = 0; + OString aStr; + css::uno::Sequence<sal_Int8> aValue; + sal_uInt8 nHeader[4]; + const bool bBinary = aVariable.getTypeKind() == DataType::LONGVARBINARY && m_aMemoHeader.db_typ == MemoFoxPro; + if ( bBinary ) + { + aValue = aVariable.getSequence(); + nSize = aValue.getLength(); + } + else + { + nSize = DBTypeConversion::convertUnicodeString( aVariable.getString(), aStr, m_eEncoding ); + } + + // append or overwrite + bool bAppend = rBlockNr == 0; + + if (!bAppend) + { + switch (m_aMemoHeader.db_typ) + { + case MemodBaseIII: // dBase III-Memofield, ends with 2 * Ctrl-Z + bAppend = nSize > (512 - 2); + break; + case MemoFoxPro: + case MemodBaseIV: // dBase IV-Memofield with length + { + char sHeader[4]; + m_pMemoStream->Seek(rBlockNr * m_aMemoHeader.db_size); + m_pMemoStream->SeekRel(4); + m_pMemoStream->ReadBytes(sHeader, 4); + + std::size_t nOldSize; + if (m_aMemoHeader.db_typ == MemoFoxPro) + nOldSize = ((static_cast<unsigned char>(sHeader[0]) * 256 + + static_cast<unsigned char>(sHeader[1])) * 256 + + static_cast<unsigned char>(sHeader[2])) * 256 + + static_cast<unsigned char>(sHeader[3]); + else + nOldSize = ((static_cast<unsigned char>(sHeader[3]) * 256 + + static_cast<unsigned char>(sHeader[2])) * 256 + + static_cast<unsigned char>(sHeader[1])) * 256 + + static_cast<unsigned char>(sHeader[0]) - 8; + + // fits the new length in the used blocks + std::size_t nUsedBlocks = ((nSize + 8) / m_aMemoHeader.db_size) + (((nSize + 8) % m_aMemoHeader.db_size > 0) ? 1 : 0), + nOldUsedBlocks = ((nOldSize + 8) / m_aMemoHeader.db_size) + (((nOldSize + 8) % m_aMemoHeader.db_size > 0) ? 1 : 0); + bAppend = nUsedBlocks > nOldUsedBlocks; + } + } + } + + if (bAppend) + { + sal_uInt64 const nStreamSize = m_pMemoStream->TellEnd(); + // fill last block + rBlockNr = (nStreamSize / m_aMemoHeader.db_size) + ((nStreamSize % m_aMemoHeader.db_size) > 0 ? 1 : 0); + + m_pMemoStream->SetStreamSize(rBlockNr * m_aMemoHeader.db_size); + m_pMemoStream->Seek(STREAM_SEEK_TO_END); + } + else + { + m_pMemoStream->Seek(rBlockNr * m_aMemoHeader.db_size); + } + + switch (m_aMemoHeader.db_typ) + { + case MemodBaseIII: // dBase III-Memofield, ends with Ctrl-Z + { + const char cEOF = char(DBF_EOL); + nSize++; + m_pMemoStream->WriteBytes(aStr.getStr(), aStr.getLength()); + m_pMemoStream->WriteChar( cEOF ).WriteChar( cEOF ); + } break; + case MemoFoxPro: + case MemodBaseIV: // dBase IV-Memofield with length + { + if ( MemodBaseIV == m_aMemoHeader.db_typ ) + (*m_pMemoStream).WriteUChar( 0xFF ) + .WriteUChar( 0xFF ) + .WriteUChar( 0x08 ); + else + (*m_pMemoStream).WriteUChar( 0x00 ) + .WriteUChar( 0x00 ) + .WriteUChar( 0x00 ); + + sal_uInt32 nWriteSize = nSize; + if (m_aMemoHeader.db_typ == MemoFoxPro) + { + if ( bBinary ) + (*m_pMemoStream).WriteUChar( 0x00 ); // Picture + else + (*m_pMemoStream).WriteUChar( 0x01 ); // Memo + for (int i = 4; i > 0; nWriteSize >>= 8) + nHeader[--i] = static_cast<sal_uInt8>(nWriteSize % 256); + } + else + { + (*m_pMemoStream).WriteUChar( 0x00 ); + nWriteSize += 8; + for (int i = 0; i < 4; nWriteSize >>= 8) + nHeader[i++] = static_cast<sal_uInt8>(nWriteSize % 256); + } + + m_pMemoStream->WriteBytes(nHeader, 4); + if ( bBinary ) + m_pMemoStream->WriteBytes(aValue.getConstArray(), aValue.getLength()); + else + m_pMemoStream->WriteBytes(aStr.getStr(), aStr.getLength()); + m_pMemoStream->Flush(); + } + } + + + // Write the new block number + if (bAppend) + { + sal_uInt64 const nStreamSize = m_pMemoStream->TellEnd(); + m_aMemoHeader.db_next = (nStreamSize / m_aMemoHeader.db_size) + ((nStreamSize % m_aMemoHeader.db_size) > 0 ? 1 : 0); + + // Write the new block number + m_pMemoStream->Seek(0); + (*m_pMemoStream).WriteUInt32( m_aMemoHeader.db_next ); + m_pMemoStream->Flush(); + } +} + + +// XAlterTable +void SAL_CALL ODbaseTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed); + + + Reference<XDataDescriptorFactory> xOldColumn; + m_xColumns->getByName(colName) >>= xOldColumn; + + try + { + alterColumn(m_xColumns->findColumn(colName)-1,descriptor,xOldColumn); + } + catch (const css::lang::IndexOutOfBoundsException&) + { + throw NoSuchElementException(colName, *this); + } +} + +void SAL_CALL ODbaseTable::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed); + + if(index < 0 || index >= m_xColumns->getCount()) + throw IndexOutOfBoundsException(OUString::number(index),*this); + + Reference<XDataDescriptorFactory> xOldColumn; + m_xColumns->getByIndex(index) >>= xOldColumn; + alterColumn(index,descriptor,xOldColumn); +} + +void ODbaseTable::alterColumn(sal_Int32 index, + const Reference< XPropertySet >& descriptor , + const Reference< XDataDescriptorFactory >& xOldColumn ) +{ + if(index < 0 || index >= m_xColumns->getCount()) + throw IndexOutOfBoundsException(OUString::number(index),*this); + + ODbaseTable* pNewTable = nullptr; + try + { + OSL_ENSURE(descriptor.is(),"ODbaseTable::alterColumn: descriptor can not be null!"); + // creates a copy of the original column and copy all properties from descriptor in xCopyColumn + Reference<XPropertySet> xCopyColumn; + if(xOldColumn.is()) + xCopyColumn = xOldColumn->createDataDescriptor(); + else + xCopyColumn = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()); + + ::comphelper::copyProperties(descriptor,xCopyColumn); + + // creates a temp file + + OUString sTempName = createTempFile(); + + pNewTable = new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection)); + Reference<XPropertySet> xHoldTable = pNewTable; + pNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),makeAny(sTempName)); + Reference<XAppend> xAppend(pNewTable->getColumns(),UNO_QUERY); + OSL_ENSURE(xAppend.is(),"ODbaseTable::alterColumn: No XAppend interface!"); + + // copy the structure + sal_Int32 i=0; + for(;i < index;++i) + { + Reference<XPropertySet> xProp; + m_xColumns->getByIndex(i) >>= xProp; + Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY); + Reference<XPropertySet> xCpy; + if(xColumn.is()) + xCpy = xColumn->createDataDescriptor(); + else + xCpy = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()); + ::comphelper::copyProperties(xProp,xCpy); + xAppend->appendByDescriptor(xCpy); + } + ++i; // now insert our new column + xAppend->appendByDescriptor(xCopyColumn); + + for(;i < m_xColumns->getCount();++i) + { + Reference<XPropertySet> xProp; + m_xColumns->getByIndex(i) >>= xProp; + Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY); + Reference<XPropertySet> xCpy; + if(xColumn.is()) + xCpy = xColumn->createDataDescriptor(); + else + xCpy = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers()); + ::comphelper::copyProperties(xProp,xCpy); + xAppend->appendByDescriptor(xCpy); + } + + // construct the new table + if(!pNewTable->CreateImpl()) + { + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_COLUMN_NOT_ALTERABLE, + "$columnname$", ::comphelper::getString(descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))) + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + + pNewTable->construct(); + + // copy the data + copyData(pNewTable,0); + + // now drop the old one + if( DropImpl() ) // we don't want to delete the memo columns too + { + try + { + // rename the new one to the old one + pNewTable->renameImpl(m_Name); + } + catch(const css::container::ElementExistException&) + { + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_DELETE_FILE, + "$filename$", m_Name + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + // release the temp file + pNewTable = nullptr; + ::comphelper::disposeComponent(xHoldTable); + } + else + { + pNewTable = nullptr; + } + FileClose(); + construct(); + if(m_xColumns) + m_xColumns->refresh(); + + } + catch(const SQLException&) + { + throw; + } + catch(const Exception&) + { + SAL_WARN( "connectivity.drivers","ODbaseTable::alterColumn: Exception occurred!"); + throw; + } +} + +Reference< XDatabaseMetaData> ODbaseTable::getMetaData() const +{ + return getConnection()->getMetaData(); +} + +void SAL_CALL ODbaseTable::rename( const OUString& newName ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed); + if(m_pTables && m_pTables->hasByName(newName)) + throw ElementExistException(newName,*this); + + + renameImpl(newName); + + ODbaseTable_BASE::rename(newName); + + construct(); + if(m_xColumns) + m_xColumns->refresh(); +} +namespace +{ + void renameFile(file::OConnection const * _pConenction,const OUString& oldName, + const OUString& newName,const OUString& _sExtension) + { + OUString aName = ODbaseTable::getEntry(_pConenction,oldName); + if(aName.isEmpty()) + { + OUString aIdent = _pConenction->getContent()->getIdentifier()->getContentIdentifier(); + if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) ) + aIdent += "/"; + aIdent += oldName; + aName = aIdent; + } + INetURLObject aURL; + aURL.SetURL(aName); + + aURL.setExtension( _sExtension ); + OUString sNewName(newName + "." + _sExtension); + + try + { + Content aContent(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext()); + + Sequence< PropertyValue > aProps( 1 ); + aProps[0].Name = "Title"; + aProps[0].Handle = -1; // n/a + aProps[0].Value <<= sNewName; + Sequence< Any > aValues; + aContent.executeCommand( "setPropertyValues",makeAny(aProps) ) >>= aValues; + if(aValues.hasElements() && aValues[0].hasValue()) + throw Exception("setPropertyValues returned non-zero", nullptr); + } + catch(const Exception&) + { + throw ElementExistException(newName); + } + } +} + +void ODbaseTable::renameImpl( const OUString& newName ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + FileClose(); + + + renameFile(m_pConnection,m_Name,newName,m_pConnection->getExtension()); + if ( HasMemoFields() ) + { // delete the memo fields + renameFile(m_pConnection,m_Name,newName,"dbt"); + } +} + +void ODbaseTable::addColumn(const Reference< XPropertySet >& _xNewColumn) +{ + OUString sTempName = createTempFile(); + + rtl::Reference xNewTable(new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection))); + xNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),makeAny(sTempName)); + { + Reference<XAppend> xAppend(xNewTable->getColumns(),UNO_QUERY); + bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(); + // copy the structure + for(sal_Int32 i=0;i < m_xColumns->getCount();++i) + { + Reference<XPropertySet> xProp; + m_xColumns->getByIndex(i) >>= xProp; + Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY); + Reference<XPropertySet> xCpy; + if(xColumn.is()) + xCpy = xColumn->createDataDescriptor(); + else + { + xCpy = new OColumn(bCase); + ::comphelper::copyProperties(xProp,xCpy); + } + + xAppend->appendByDescriptor(xCpy); + } + Reference<XPropertySet> xCpy = new OColumn(bCase); + ::comphelper::copyProperties(_xNewColumn,xCpy); + xAppend->appendByDescriptor(xCpy); + } + + // construct the new table + if(!xNewTable->CreateImpl()) + { + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_COLUMN_NOT_ADDABLE, + "$columnname$", ::comphelper::getString(_xNewColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))) + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + + xNewTable->construct(); + // copy the data + copyData(xNewTable.get(),xNewTable->m_xColumns->getCount()); + // drop the old table + if(DropImpl()) + { + xNewTable->renameImpl(m_Name); + // release the temp file + } + xNewTable.clear(); + + FileClose(); + construct(); + if(m_xColumns) + m_xColumns->refresh(); +} + +void ODbaseTable::dropColumn(sal_Int32 _nPos) +{ + OUString sTempName = createTempFile(); + + rtl::Reference xNewTable(new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection))); + xNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),makeAny(sTempName)); + { + Reference<XAppend> xAppend(xNewTable->getColumns(),UNO_QUERY); + bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(); + // copy the structure + for(sal_Int32 i=0;i < m_xColumns->getCount();++i) + { + if(_nPos != i) + { + Reference<XPropertySet> xProp; + m_xColumns->getByIndex(i) >>= xProp; + Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY); + Reference<XPropertySet> xCpy; + if(xColumn.is()) + xCpy = xColumn->createDataDescriptor(); + else + { + xCpy = new OColumn(bCase); + ::comphelper::copyProperties(xProp,xCpy); + } + xAppend->appendByDescriptor(xCpy); + } + } + } + + // construct the new table + if(!xNewTable->CreateImpl()) + { + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_COLUMN_NOT_DROP, + "$position$", OUString::number(_nPos) + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + xNewTable->construct(); + // copy the data + copyData(xNewTable.get(),_nPos); + // drop the old table + if(DropImpl()) + xNewTable->renameImpl(m_Name); + // release the temp file + + xNewTable.clear(); + + FileClose(); + construct(); +} + +OUString ODbaseTable::createTempFile() +{ + OUString aIdent = m_pConnection->getContent()->getIdentifier()->getContentIdentifier(); + if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) ) + aIdent += "/"; + + OUString sTempName(aIdent); + OUString sExt("." + m_pConnection->getExtension()); + OUString sName(m_Name); + TempFile aTempFile(sName, true, &sExt, &sTempName); + if(!aTempFile.IsValid()) + getConnection()->throwGenericSQLException(STR_COULD_NOT_ALTER_TABLE, *this); + + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + aURL.SetURL(aTempFile.GetURL()); + + OUString sNewName(aURL.getName().copy(0, aURL.getName().getLength() - sExt.getLength())); + + return sNewName; +} + +void ODbaseTable::copyData(ODbaseTable* _pNewTable,sal_Int32 _nPos) +{ + sal_Int32 nPos = _nPos + 1; // +1 because we always have the bookmark column as well + OValueRefRow aRow = new OValueRefVector(m_xColumns->getCount()); + OValueRefRow aInsertRow; + if(_nPos) + { + aInsertRow = new OValueRefVector(_pNewTable->m_xColumns->getCount()); + std::for_each(aInsertRow->begin(),aInsertRow->end(),TSetRefBound(true)); + } + else + aInsertRow = aRow; + + // we only have to bind the values which we need to copy into the new table + std::for_each(aRow->begin(),aRow->end(),TSetRefBound(true)); + if(_nPos && (_nPos < static_cast<sal_Int32>(aRow->size()))) + (*aRow)[nPos]->setBound(false); + + + sal_Int32 nCurPos; + OValueRefVector::const_iterator aIter; + for(sal_uInt32 nRowPos = 0; nRowPos < m_aHeader.nbRecords;++nRowPos) + { + bool bOk = seekRow( IResultSetHelper::BOOKMARK, nRowPos+1, nCurPos ); + if ( bOk ) + { + bOk = fetchRow( aRow, *m_aColumns, true); + if ( bOk && !aRow->isDeleted() ) // copy only not deleted rows + { + // special handling when pos == 0 then we don't have to distinguish between the two rows + if(_nPos) + { + aIter = aRow->begin()+1; + sal_Int32 nCount = 1; + for(OValueRefVector::iterator aInsertIter = aInsertRow->begin()+1; aIter != aRow->end() && aInsertIter != aInsertRow->end();++aIter,++nCount) + { + if(nPos != nCount) + { + (*aInsertIter)->setValue( (*aIter)->getValue() ); + ++aInsertIter; + } + } + } + bOk = _pNewTable->InsertRow(*aInsertRow,_pNewTable->m_xColumns.get()); + SAL_WARN_IF(!bOk, "connectivity.drivers", "Row could not be inserted!"); + } + else + { + SAL_WARN_IF(!bOk, "connectivity.drivers", "Row could not be fetched!"); + } + } + else + { + OSL_ASSERT(false); + } + } // for(sal_uInt32 nRowPos = 0; nRowPos < m_aHeader.db_anz;++nRowPos) +} + +void ODbaseTable::throwInvalidDbaseFormat() +{ + FileClose(); + // no dbase file + + const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution( + STR_INVALID_DBASE_FILE, + "$filename$", getEntry(m_pConnection,m_Name) + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); +} + +void ODbaseTable::refreshHeader() +{ + if ( m_aHeader.nbRecords == 0 ) + readHeader(); +} + +bool ODbaseTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) +{ + // prepare positioning: + OSL_ENSURE(m_pFileStream,"ODbaseTable::seekRow: FileStream is NULL!"); + + sal_uInt32 nNumberOfRecords = m_aHeader.nbRecords; + sal_uInt32 nTempPos = m_nFilePos; + m_nFilePos = nCurPos; + + switch(eCursorPosition) + { + case IResultSetHelper::NEXT: + ++m_nFilePos; + break; + case IResultSetHelper::PRIOR: + if (m_nFilePos > 0) + --m_nFilePos; + break; + case IResultSetHelper::FIRST: + m_nFilePos = 1; + break; + case IResultSetHelper::LAST: + m_nFilePos = nNumberOfRecords; + break; + case IResultSetHelper::RELATIVE1: + m_nFilePos = (m_nFilePos + nOffset < 0) ? 0 + : static_cast<sal_uInt32>(m_nFilePos + nOffset); + break; + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::BOOKMARK: + m_nFilePos = static_cast<sal_uInt32>(nOffset); + break; + } + + if (m_nFilePos > static_cast<sal_Int32>(nNumberOfRecords)) + m_nFilePos = static_cast<sal_Int32>(nNumberOfRecords) + 1; + + if (m_nFilePos == 0 || m_nFilePos == static_cast<sal_Int32>(nNumberOfRecords) + 1) + goto Error; + else + { + std::size_t nEntryLen = m_aHeader.recordLength; + + OSL_ENSURE(m_nFilePos >= 1,"SdbDBFCursor::FileFetchRow: invalid record position"); + std::size_t nPos = m_aHeader.headerLength + static_cast<std::size_t>(m_nFilePos-1) * nEntryLen; + + m_pFileStream->Seek(nPos); + if (m_pFileStream->GetError() != ERRCODE_NONE) + goto Error; + + std::size_t nRead = m_pFileStream->ReadBytes(m_pBuffer.get(), nEntryLen); + if (nRead != nEntryLen) + { + SAL_WARN("connectivity.drivers", "ODbaseTable::seekRow: short read!"); + goto Error; + } + if (m_pFileStream->GetError() != ERRCODE_NONE) + goto Error; + } + goto End; + +Error: + switch(eCursorPosition) + { + case IResultSetHelper::PRIOR: + case IResultSetHelper::FIRST: + m_nFilePos = 0; + break; + case IResultSetHelper::LAST: + case IResultSetHelper::NEXT: + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::RELATIVE1: + if (nOffset > 0) + m_nFilePos = nNumberOfRecords + 1; + else if (nOffset < 0) + m_nFilePos = 0; + break; + case IResultSetHelper::BOOKMARK: + m_nFilePos = nTempPos; // last position + } + return false; + +End: + nCurPos = m_nFilePos; + return true; +} + +bool ODbaseTable::ReadMemo(std::size_t nBlockNo, ORowSetValue& aVariable) +{ + m_pMemoStream->Seek(nBlockNo * m_aMemoHeader.db_size); + switch (m_aMemoHeader.db_typ) + { + case MemodBaseIII: // dBase III-Memofield, ends with Ctrl-Z + { + const char cEOF = char(DBF_EOL); + OStringBuffer aBStr; + static char aBuf[514]; + aBuf[512] = 0; // avoid random value + bool bReady = false; + + do + { + m_pMemoStream->ReadBytes(&aBuf, 512); + + sal_uInt16 i = 0; + while (aBuf[i] != cEOF && ++i < 512) + ; + bReady = aBuf[i] == cEOF; + + aBuf[i] = 0; + aBStr.append(aBuf); + + } while (!bReady && !m_pMemoStream->eof()); + + aVariable = OStringToOUString(aBStr.makeStringAndClear(), + m_eEncoding); + + } break; + case MemoFoxPro: + case MemodBaseIV: // dBase IV-Memofield with length + { + bool bIsText = true; + char sHeader[4]; + m_pMemoStream->ReadBytes(sHeader, 4); + // Foxpro stores text and binary data + if (m_aMemoHeader.db_typ == MemoFoxPro) + { + bIsText = sHeader[3] != 0; + } + else if (static_cast<sal_uInt8>(sHeader[0]) != 0xFF || static_cast<sal_uInt8>(sHeader[1]) != 0xFF || static_cast<sal_uInt8>(sHeader[2]) != 0x08) + { + return false; + } + + sal_uInt32 nLength(0); + (*m_pMemoStream).ReadUInt32( nLength ); + + if (m_aMemoHeader.db_typ == MemodBaseIV) + nLength -= 8; + + if ( nLength ) + { + if ( bIsText ) + { + OStringBuffer aBuffer(read_uInt8s_ToOString(*m_pMemoStream, nLength)); + //pad it out with ' ' to expected length on short read + sal_Int32 nRequested = sal::static_int_cast<sal_Int32>(nLength); + comphelper::string::padToLength(aBuffer, nRequested, ' '); + aVariable = OStringToOUString(aBuffer.makeStringAndClear(), m_eEncoding); + } // if ( bIsText ) + else + { + css::uno::Sequence< sal_Int8 > aData(nLength); + m_pMemoStream->ReadBytes(aData.getArray(), nLength); + aVariable = aData; + } + } // if ( nLength ) + } + } + return true; +} + +bool ODbaseTable::AllocBuffer() +{ + sal_uInt16 nSize = m_aHeader.recordLength; + SAL_WARN_IF(nSize == 0, "connectivity.drivers", "Size too small"); + + if (m_nBufferSize != nSize) + { + m_pBuffer.reset(); + } + + // if there is no buffer available: allocate: + if (!m_pBuffer && nSize > 0) + { + m_nBufferSize = nSize; + m_pBuffer.reset(new sal_uInt8[m_nBufferSize+1]); + } + + return m_pBuffer != nullptr; +} + +bool ODbaseTable::WriteBuffer() +{ + OSL_ENSURE(m_nFilePos >= 1,"SdbDBFCursor::FileFetchRow: invalid record position"); + + // position on desired record: + std::size_t nPos = m_aHeader.headerLength + static_cast<long>(m_nFilePos-1) * m_aHeader.recordLength; + m_pFileStream->Seek(nPos); + return m_pFileStream->WriteBytes(m_pBuffer.get(), m_aHeader.recordLength) > 0; +} + +sal_Int32 ODbaseTable::getCurrentLastPos() const +{ + return m_aHeader.nbRecords; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/DTables.cxx b/connectivity/source/drivers/dbase/DTables.cxx new file mode 100644 index 000000000..1d9229694 --- /dev/null +++ b/connectivity/source/drivers/dbase/DTables.cxx @@ -0,0 +1,128 @@ +/* -*- 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 <dbase/DConnection.hxx> +#include <dbase/DTables.hxx> +#include <dbase/DTable.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <file/FCatalog.hxx> +#include <file/FConnection.hxx> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <dbase/DCatalog.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <strings.hrc> +#include <connectivity/dbexception.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::dbase; +using namespace connectivity::file; +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::lang; +using namespace ::com::sun::star::container; + +sdbcx::ObjectType ODbaseTables::createObject(const OUString& _rName) +{ + ODbaseTable* pRet = new ODbaseTable(this, static_cast<ODbaseConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection()), + _rName,"TABLE"); + + sdbcx::ObjectType xRet = pRet; + pRet->construct(); + return xRet; +} + +void ODbaseTables::impl_refresh( ) +{ + static_cast<ODbaseCatalog*>(&m_rParent)->refreshTables(); +} + +Reference< XPropertySet > ODbaseTables::createDescriptor() +{ + return new ODbaseTable(this, static_cast<ODbaseConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection())); +} + +// XAppend +sdbcx::ObjectType ODbaseTables::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + auto pTable = comphelper::getUnoTunnelImplementation<ODbaseTable>(descriptor); + if(pTable) + { + pTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),makeAny(_rForName)); + try + { + if(!pTable->CreateImpl()) + throw SQLException(); + } + catch(SQLException&) + { + throw; + } + catch(Exception& ex) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw SQLException( ex.Message, nullptr, "", 0, anyEx ); + } + } + return createObject( _rForName ); +} + +// XDrop +void ODbaseTables::dropObject(sal_Int32 _nPos, const OUString& _sElementName) +{ + Reference< XUnoTunnel> xTunnel; + try + { + xTunnel.set(getObject(_nPos),UNO_QUERY); + } + catch(const Exception&) + { + if(ODbaseTable::Drop_Static(ODbaseTable::getEntry(static_cast<OFileCatalog&>(m_rParent).getConnection(),_sElementName),false,nullptr)) + return; + } + + if ( xTunnel.is() ) + { + ODbaseTable* pTable = reinterpret_cast< ODbaseTable* >( xTunnel->getSomething(ODbaseTable::getUnoTunnelId()) ); + if(pTable) + pTable->DropImpl(); + } + else + { + const OUString sError( static_cast<OFileCatalog&>(m_rParent).getConnection()->getResources().getResourceStringWithSubstitution( + STR_TABLE_NOT_DROP, + "$tablename$", _sElementName + ) ); + ::dbtools::throwGenericSQLException( sError, nullptr ); + } +} + +Any SAL_CALL ODbaseTables::queryInterface( const Type & rType ) +{ + typedef sdbcx::OCollection OTables_BASE; + return OTables_BASE::queryInterface(rType); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/Dservices.cxx b/connectivity/source/drivers/dbase/Dservices.cxx new file mode 100644 index 000000000..e2d09d6c0 --- /dev/null +++ b/connectivity/source/drivers/dbase/Dservices.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 <dbase/DDriver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::dbase; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* dbase_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + ODriver::getImplementationName_Static(), + ODriver::getSupportedServiceNames_Static(), + ODriver_CreateInstance, ::cppu::createSingleFactory) + ; + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/dbase/dbase.component b/connectivity/source/drivers/dbase/dbase.component new file mode 100644 index 000000000..3f2cea66b --- /dev/null +++ b/connectivity/source/drivers/dbase/dbase.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="dbase" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.dbase.ODriver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/dbase/dindexnode.cxx b/connectivity/source/drivers/dbase/dindexnode.cxx new file mode 100644 index 000000000..1ac10800f --- /dev/null +++ b/connectivity/source/drivers/dbase/dindexnode.cxx @@ -0,0 +1,1046 @@ +/* -*- 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 <dbase/dindexnode.hxx> +#include <dbase/DIndex.hxx> +#include <o3tl/safeint.hxx> +#include <tools/debug.hxx> +#include <tools/stream.hxx> +#include <sal/log.hxx> + +#include <algorithm> +#include <memory> + + +using namespace connectivity; +using namespace connectivity::dbase; +using namespace connectivity::file; +using namespace com::sun::star::sdbc; + +ONDXKey::ONDXKey() + :nRecord(0) +{ +} + +ONDXKey::ONDXKey(const ORowSetValue& rVal, sal_Int32 eType, sal_uInt32 nRec) + : ONDXKey_BASE(eType) + , nRecord(nRec) + , xValue(rVal) +{ +} + +ONDXKey::ONDXKey(const OUString& aStr, sal_uInt32 nRec) + : ONDXKey_BASE(css::sdbc::DataType::VARCHAR) + ,nRecord(nRec) +{ + if (!aStr.isEmpty()) + { + xValue = aStr; + xValue.setBound(true); + } +} + +ONDXKey::ONDXKey(double aVal, sal_uInt32 nRec) + : ONDXKey_BASE(css::sdbc::DataType::DOUBLE) + ,nRecord(nRec) + ,xValue(aVal) +{ +} + +// index page +ONDXPage::ONDXPage(ODbaseIndex& rInd, sal_uInt32 nPos, ONDXPage* pParent) + : nRefCount(0) + , bNoDelete(1) + , nPagePos(nPos) + , bModified(false) + , nCount(0) + , aParent(pParent) + , rIndex(rInd) +{ + sal_uInt16 nT = rIndex.getHeader().db_maxkeys; + ppNodes.reset( new ONDXNode[nT] ); +} + +ONDXPage::~ONDXPage() +{ +} + +void ONDXPage::ReleaseRef() +{ + assert( nRefCount >= 1); + if(--nRefCount == 0 && !bNoDelete) + { + QueryDelete(); + } +} + +void ONDXPage::QueryDelete() +{ + // Store in GarbageCollector + if (IsModified() && rIndex.m_pFileStream) + WriteONDXPage( *rIndex.m_pFileStream, *this ); + + bModified = false; + if (rIndex.UseCollector()) + { + if (aChild.Is()) + aChild->Release(false); + + for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++) + { + if (ppNodes[i].GetChild().Is()) + ppNodes[i].GetChild()->Release(false); + + ppNodes[i] = ONDXNode(); + } + bNoDelete = 1; + + nCount = 0; + aParent.Clear(); + rIndex.Collect(this); + } + else + { + // I'm not sure about the original purpose of this line, but right now + // it serves the purpose that anything that attempts to do an AddFirstRef() + // after an object is deleted will trip an assert. + nRefCount = 1 << 30; + delete this; + } +} + +ONDXPagePtr& ONDXPage::GetChild(ODbaseIndex const * pIndex) +{ + if (!aChild.Is() && pIndex) + { + aChild = rIndex.CreatePage(aChild.GetPagePos(),this,aChild.HasPage()); + } + return aChild; +} + + +sal_uInt16 ONDXPage::FindPos(const ONDXKey& rKey) const +{ + // searches the position for the given key in a page + sal_uInt16 i = 0; + while (i < nCount && rKey > ((*this)[i]).GetKey()) + i++; + + return i; +} + + +bool ONDXPage::Find(const ONDXKey& rKey) +{ + // searches the given key + // Speciality: At the end of the method + // the actual page and the position of the node, fulfilling the '<=' condition, are saved + // This is considered at insert. + sal_uInt16 i = 0; + while (i < nCount && rKey > ((*this)[i]).GetKey()) + i++; + + bool bResult = false; + + if (!IsLeaf()) + { + // descend further + ONDXPagePtr aPage = (i==0) ? GetChild(&rIndex) : ((*this)[i-1]).GetChild(&rIndex, this); + bResult = aPage.Is() && aPage->Find(rKey); + } + else if (i == nCount) + { + rIndex.m_aCurLeaf = this; + rIndex.m_nCurNode = i - 1; + bResult = false; + } + else + { + bResult = rKey == ((*this)[i]).GetKey(); + rIndex.m_aCurLeaf = this; + rIndex.m_nCurNode = bResult ? i : i - 1; + } + return bResult; +} + + +bool ONDXPage::Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft) +{ + // When creating an index there can be multiple nodes added, + // these are sorted ascending + bool bAppend = nRowsLeft > 0; + if (IsFull()) + { + ONDXNode aSplitNode; + if (bAppend) + aSplitNode = rNode; + else + { + // Save the last node + aSplitNode = (*this)[nCount-1]; + if(rNode.GetKey() <= aSplitNode.GetKey()) + { + bool bResult = true; + // this practically reduces the number of nodes by 1 + if (IsLeaf() && this == rIndex.m_aCurLeaf) + { + // assumes, that the node, for which the condition (<=) holds, is stored in m_nCurNode + --nCount; // (otherwise we might get Assertions and GPFs - 60593) + bResult = Insert(rIndex.m_nCurNode + 1, rNode); + } + else // position unknown + { + sal_uInt16 nPos = NODE_NOTFOUND; + while (++nPos < nCount && rNode.GetKey() > ((*this)[nPos]).GetKey()) ; + + --nCount; // (otherwise we might get Assertions and GPFs - 60593) + bResult = Insert(nPos, rNode); + } + + // can the new node be inserted + if (!bResult) + { + nCount++; + aSplitNode = rNode; + } + } + else + aSplitNode = rNode; + } + + sal_uInt32 nNewPagePos = rIndex.GetPageCount(); + sal_uInt32 nNewPageCount = nNewPagePos + 1; + + // insert extracted node into parent node + if (!HasParent()) + { + // No parent, then new root + ONDXPagePtr aNewRoot = rIndex.CreatePage(nNewPagePos + 1); + aNewRoot->SetChild(this); + + rIndex.m_aRoot = aNewRoot; + rIndex.SetRootPos(nNewPagePos + 1); + rIndex.SetPageCount(++nNewPageCount); + } + + // create new leaf and divide page + ONDXPagePtr aNewPage = rIndex.CreatePage(nNewPagePos,aParent); + rIndex.SetPageCount(nNewPageCount); + + // How many nodes are being inserted? + // Enough, then we can fill the page to the brim + ONDXNode aInnerNode; + if (!IsLeaf() || nRowsLeft < o3tl::make_unsigned(rIndex.GetMaxNodes() / 2)) + aInnerNode = Split(*aNewPage); + else + { + aInnerNode = (*this)[nCount - 1]; + + // Node points to the new page + aInnerNode.SetChild(aNewPage); + + // Inner nodes have no record number + if (rIndex.isUnique()) + aInnerNode.GetKey().ResetRecord(); + + // new page points to the page of the extracted node + if (!IsLeaf()) + aNewPage->SetChild(aInnerNode.GetChild()); + } + + aNewPage->Append(aSplitNode); + ONDXPagePtr aTempParent = aParent; + if (IsLeaf()) + { + rIndex.m_aCurLeaf = aNewPage; + rIndex.m_nCurNode = rIndex.m_aCurLeaf->Count() - 1; + + // free not needed pages, there are no references to those on the page + // afterwards 'this' can't be valid anymore!!! + ReleaseFull(); + } + + // Insert extracted node + return aTempParent->Insert(aInnerNode); + } + else // Fill the page up + { + if (bAppend) + { + if (IsLeaf()) + rIndex.m_nCurNode = nCount - 1; + return Append(rNode); + } + else + { + sal_uInt16 nNodePos = FindPos(rNode.GetKey()); + if (IsLeaf()) + rIndex.m_nCurNode = nNodePos; + + return Insert(nNodePos, rNode); + } + } +} + + +bool ONDXPage::Insert(sal_uInt16 nPos, ONDXNode& rNode) +{ + sal_uInt16 nMaxCount = rIndex.getHeader().db_maxkeys; + if (nPos >= nMaxCount) + return false; + + if (nCount) + { + ++nCount; + // shift right + for (sal_uInt16 i = std::min(static_cast<sal_uInt16>(nMaxCount-1), static_cast<sal_uInt16>(nCount-1)); nPos < i; --i) + (*this)[i] = (*this)[i-1]; + } + else + if (nCount < nMaxCount) + nCount++; + + // insert at the position + ONDXNode& rInsertNode = (*this)[nPos]; + rInsertNode = rNode; + if (rInsertNode.GetChild().Is()) + { + rInsertNode.GetChild()->SetParent(this); + rNode.GetChild()->SetParent(this); + } + + bModified = true; + + return true; +} + + +bool ONDXPage::Append(ONDXNode& rNode) +{ + DBG_ASSERT(!IsFull(), "no Append possible"); + return Insert(nCount, rNode); +} + +void ONDXPage::Release(bool bSave) +{ + // free pages + if (aChild.Is()) + aChild->Release(bSave); + + // free pointer + aChild.Clear(); + + for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++) + { + if (ppNodes[i].GetChild()) + ppNodes[i].GetChild()->Release(bSave); + + ppNodes[i].GetChild().Clear(); + } + aParent.Clear(); +} + +void ONDXPage::ReleaseFull() +{ + ONDXPagePtr aTempParent = aParent; + Release(); + + if (aTempParent.Is()) + { + // Free pages not needed, there will be no reference anymore to the pages + // afterwards 'this' can't be valid anymore!!! + sal_uInt16 nParentPos = aTempParent->Search(this); + if (nParentPos != NODE_NOTFOUND) + (*aTempParent)[nParentPos].GetChild().Clear(); + else + aTempParent->GetChild().Clear(); + } +} + +void ONDXPage::Delete(sal_uInt16 nNodePos) +{ + if (IsLeaf()) + { + // The last element will not be deleted + if (nNodePos == (nCount - 1)) + { + ONDXNode aNode = (*this)[nNodePos]; + + // parent's KeyValue has to be replaced + if (HasParent()) + aParent->SearchAndReplace(aNode.GetKey(), + (*this)[nNodePos-1].GetKey()); + } + } + + // Delete the node + Remove(nNodePos); + + // Underflow + if (HasParent() && nCount < (rIndex.GetMaxNodes() / 2)) + { + // determine, which node points to the page + sal_uInt16 nParentNodePos = aParent->Search(this); + // last element on parent-page -> merge with secondlast page + if (nParentNodePos == (aParent->Count() - 1)) + { + if (!nParentNodePos) + // merge with left neighbour + Merge(nParentNodePos,aParent->GetChild(&rIndex)); + else + Merge(nParentNodePos,(*aParent)[nParentNodePos-1].GetChild(&rIndex,aParent)); + } + // otherwise merge page with next page + else + { + // merge with right neighbour + Merge(nParentNodePos + 1,((*aParent)[nParentNodePos + 1].GetChild(&rIndex,aParent))); + nParentNodePos++; + } + if (HasParent() && !(*aParent)[nParentNodePos].HasChild()) + aParent->Delete(nParentNodePos); + } + else if (IsRoot()) + // make sure that the position of the root is kept + rIndex.SetRootPos(nPagePos); +} + + +ONDXNode ONDXPage::Split(ONDXPage& rPage) +{ + DBG_ASSERT(IsFull(), "Incorrect Splitting"); + /* divide one page into two + leaf: + Page 1 is (n - (n/2)) + Page 2 is (n/2) + Node n/2 will be duplicated + inner node: + Page 1 is (n+1)/2 + Page 2 is (n/2-1) + Node ((n+1)/2 + 1) : will be taken out + */ + ONDXNode aResultNode; + if (IsLeaf()) + { + for (sal_uInt16 i = nCount - (nCount / 2), j = 0 ; i < nCount; i++) + rPage.Insert(j++,(*this)[i]); + + // this node contains a key that already exists in the tree and must be replaced + ONDXNode aLastNode = (*this)[nCount - 1]; + nCount = nCount - (nCount / 2); + aResultNode = (*this)[nCount - 1]; + + if (HasParent()) + aParent->SearchAndReplace(aLastNode.GetKey(), + aResultNode.GetKey()); + } + else + { + for (sal_uInt16 i = (nCount + 1) / 2 + 1, j = 0 ; i < nCount; i++) + rPage.Insert(j++,(*this)[i]); + + aResultNode = (*this)[(nCount + 1) / 2]; + nCount = (nCount + 1) / 2; + + // new page points to page with extracted node + rPage.SetChild(aResultNode.GetChild()); + } + // node points to new page + aResultNode.SetChild(&rPage); + + // inner nodes have no record number + if (rIndex.isUnique()) + aResultNode.GetKey().ResetRecord(); + bModified = true; + return aResultNode; +} + + +void ONDXPage::Merge(sal_uInt16 nParentNodePos, const ONDXPagePtr& xPage) +{ + DBG_ASSERT(HasParent(), "no parent existing"); + DBG_ASSERT(nParentNodePos != NODE_NOTFOUND, "Wrong index setup"); + + /* Merge 2 pages */ + sal_uInt16 nMaxNodes = rIndex.GetMaxNodes(), + nMaxNodes_2 = nMaxNodes / 2; + + // Determine if page is right or left neighbour + bool bRight = ((*xPage)[0].GetKey() > (*this)[0].GetKey()); // sal_True, whenn xPage the right side is + sal_uInt16 nNewCount = (*xPage).Count() + Count(); + + if (IsLeaf()) + { + // Condition for merge + if (nNewCount < (nMaxNodes_2 * 2)) + { + sal_uInt16 nLastNode = bRight ? Count() - 1 : xPage->Count() - 1; + if (bRight) + { + DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop"); + // shift all nodes from xPage to the left node (append) + while (xPage->Count()) + { + Append((*xPage)[0]); + xPage->Remove(0); + } + } + else + { + DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop"); + // xPage is the left page and THIS the right one + while (xPage->Count()) + { + Insert(0,(*xPage)[xPage->Count()-1]); + xPage->Remove(xPage->Count()-1); + } + // replace old position of xPage in parent with this + if (nParentNodePos) + (*aParent)[nParentNodePos-1].SetChild(this,aParent); + else // or set as right node + aParent->SetChild(this); + aParent->SetModified(true); + + } + + // cancel Child-relationship at parent node + (*aParent)[nParentNodePos].SetChild(); + // replace the Node-value, only if changed page is the left one, otherwise become + if(aParent->IsRoot() && aParent->Count() == 1) + { + (*aParent)[0].SetChild(); + aParent->ReleaseFull(); + aParent.Clear(); + rIndex.SetRootPos(nPagePos); + rIndex.m_aRoot = this; + SetModified(true); + } + else + aParent->SearchAndReplace((*this)[nLastNode].GetKey(),(*this)[nCount-1].GetKey()); + + xPage->SetModified(false); + xPage->ReleaseFull(); // is not needed anymore + } + // balance the elements nNewCount >= (nMaxNodes_2 * 2) + else + { + if (bRight) + { + // shift all nodes from xPage to the left node (append) + ONDXNode aReplaceNode = (*this)[nCount - 1]; + while (nCount < nMaxNodes_2) + { + Append((*xPage)[0]); + xPage->Remove(0); + } + // Replace the node values: replace old last value by the last of xPage + aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[nCount-1].GetKey()); + } + else + { + // insert all nodes from this in front of the xPage nodes + ONDXNode aReplaceNode = (*this)[nCount - 1]; + while (xPage->Count() < nMaxNodes_2) + { + xPage->Insert(0,(*this)[nCount-1]); + Remove(nCount-1); + } + // Replace the node value + aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[Count()-1].GetKey()); + } + } + } + else // !IsLeaf() + { + // Condition for merge + if (nNewCount < nMaxNodes_2 * 2) + { + if (bRight) + { + DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop"); + // Parent node will be integrated; is initialized with Child from xPage + (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent); + Append((*aParent)[nParentNodePos]); + for (sal_uInt16 i = 0 ; i < xPage->Count(); i++) + Append((*xPage)[i]); + } + else + { + DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop"); + // Parent-node will be integrated; is initialized with child + (*aParent)[nParentNodePos].SetChild(GetChild(),aParent); // Parent memorizes my child + Insert(0,(*aParent)[nParentNodePos]); // insert parent node into myself + while (xPage->Count()) + { + Insert(0,(*xPage)[xPage->Count()-1]); + xPage->Remove(xPage->Count()-1); + } + SetChild(xPage->GetChild()); + + if (nParentNodePos) + (*aParent)[nParentNodePos-1].SetChild(this,aParent); + else + aParent->SetChild(this); + } + + // afterwards parent node will be reset + (*aParent)[nParentNodePos].SetChild(); + aParent->SetModified(true); + + if(aParent->IsRoot() && aParent->Count() == 1) + { + (*aParent).SetChild(); + aParent->ReleaseFull(); + aParent.Clear(); + rIndex.SetRootPos(nPagePos); + rIndex.m_aRoot = this; + SetModified(true); + } + else if(nParentNodePos) + // replace the node value + // for Append the range will be enlarged, for Insert the old node from xPage will reference to this + // that's why the node must be updated here + aParent->SearchAndReplace((*aParent)[nParentNodePos-1].GetKey(),(*aParent)[nParentNodePos].GetKey()); + + xPage->SetModified(false); + xPage->ReleaseFull(); + } + // balance the elements + else + { + if (bRight) + { + while (nCount < nMaxNodes_2) + { + (*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent); + Append((*aParent)[nParentNodePos]); + (*aParent)[nParentNodePos] = (*xPage)[0]; + xPage->Remove(0); + } + xPage->SetChild((*aParent)[nParentNodePos].GetChild()); + (*aParent)[nParentNodePos].SetChild(xPage,aParent); + } + else + { + while (nCount < nMaxNodes_2) + { + (*aParent)[nParentNodePos].SetChild(GetChild(),aParent); + Insert(0,(*aParent)[nParentNodePos]); + (*aParent)[nParentNodePos] = (*xPage)[xPage->Count()-1]; + xPage->Remove(xPage->Count()-1); + } + SetChild((*aParent)[nParentNodePos].GetChild()); + (*aParent)[nParentNodePos].SetChild(this,aParent); + + } + aParent->SetModified(true); + } + } +} + +// ONDXNode + + +void ONDXNode::Read(SvStream &rStream, ODbaseIndex const & rIndex) +{ + rStream.ReadUInt32( aKey.nRecord ); // key + + if (rIndex.getHeader().db_keytype) + { + double aDbl; + rStream.ReadDouble( aDbl ); + aKey = ONDXKey(aDbl,aKey.nRecord); + } + else + { + sal_uInt16 nLen = rIndex.getHeader().db_keylen; + OString aBuf = read_uInt8s_ToOString(rStream, nLen); + //get length minus trailing whitespace + sal_Int32 nContentLen = aBuf.getLength(); + while (nContentLen && aBuf[nContentLen-1] == ' ') + --nContentLen; + aKey = ONDXKey(OUString(aBuf.getStr(), nContentLen, rIndex.m_pTable->getConnection()->getTextEncoding()) ,aKey.nRecord); + } + rStream >> aChild; +} + + +void ONDXNode::Write(SvStream &rStream, const ONDXPage& rPage) const +{ + const ODbaseIndex& rIndex = rPage.GetIndex(); + if (!rIndex.isUnique() || rPage.IsLeaf()) + rStream.WriteUInt32( aKey.nRecord ); // key + else + rStream.WriteUInt32( 0 ); // key + + if (rIndex.getHeader().db_keytype) // double + { + if (sizeof(double) != rIndex.getHeader().db_keylen) + { + SAL_WARN("connectivity.dbase", "this key length cannot possibly be right?"); + } + if (aKey.getValue().isNull()) + { + sal_uInt8 buf[sizeof(double)] = {}; + rStream.WriteBytes(&buf[0], sizeof(double)); + } + else + rStream.WriteDouble( static_cast<double>(aKey.getValue()) ); + } + else + { + sal_uInt16 const nLen(rIndex.getHeader().db_keylen); + std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[nLen]); + memset(&pBuf[0], 0x20, nLen); + if (!aKey.getValue().isNull()) + { + OUString sValue = aKey.getValue(); + OString aText(OUStringToOString(sValue, rIndex.m_pTable->getConnection()->getTextEncoding())); + strncpy(reinterpret_cast<char *>(&pBuf[0]), aText.getStr(), + std::min<size_t>(nLen, aText.getLength())); + } + rStream.WriteBytes(&pBuf[0], nLen); + } + WriteONDXPagePtr( rStream, aChild ); +} + + +ONDXPagePtr& ONDXNode::GetChild(ODbaseIndex* pIndex, ONDXPage* pParent) +{ + if (!aChild.Is() && pIndex) + { + aChild = pIndex->CreatePage(aChild.GetPagePos(),pParent,aChild.HasPage()); + } + return aChild; +} + + +// ONDXKey + + +bool ONDXKey::IsText(sal_Int32 eType) +{ + return eType == DataType::VARCHAR || eType == DataType::CHAR; +} + + +int ONDXKey::Compare(const ONDXKey& rKey) const +{ + sal_Int32 nRes; + + if (getValue().isNull()) + { + if (rKey.getValue().isNull() || (IsText(getDBType()) && rKey.getValue().getString().isEmpty())) + nRes = 0; + else + nRes = -1; + } + else if (rKey.getValue().isNull()) + { + if (getValue().isNull() || (IsText(getDBType()) && getValue().getString().isEmpty())) + nRes = 0; + else + nRes = 1; + } + else if (IsText(getDBType())) + { + nRes = getValue().getString().compareTo(rKey.getValue()); + } + else + { + double m = getValue(); + double n = rKey.getValue(); + nRes = (m > n) ? 1 : ( m < n) ? -1 : 0; + } + + // compare record, if index !Unique + if (nRes == 0 && nRecord && rKey.nRecord) + { + nRes = (nRecord > rKey.nRecord) ? 1 : + (nRecord == rKey.nRecord) ? 0 : -1; + } + return nRes; +} + +void ONDXKey::setValue(const ORowSetValue& _rVal) +{ + xValue = _rVal; +} + +const ORowSetValue& ONDXKey::getValue() const +{ + return xValue; +} + +SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPagePtr& rPage) +{ + rStream.ReadUInt32( rPage.nPagePos ); + return rStream; +} + +SvStream& connectivity::dbase::WriteONDXPagePtr(SvStream &rStream, const ONDXPagePtr& rPage) +{ + rStream.WriteUInt32( rPage.nPagePos ); + return rStream; +} + +// ONDXPagePtr +ONDXPagePtr::ONDXPagePtr() + : mpPage(nullptr) + , nPagePos(0) +{ +} + +ONDXPagePtr::ONDXPagePtr(ONDXPagePtr&& rRef) noexcept +{ + mpPage = rRef.mpPage; + rRef.mpPage = nullptr; + nPagePos = rRef.nPagePos; +} + +ONDXPagePtr::ONDXPagePtr(ONDXPagePtr const & rRef) + : mpPage(rRef.mpPage) + , nPagePos(rRef.nPagePos) +{ + if (mpPage != nullptr) + mpPage->AddNextRef(); +} + +ONDXPagePtr::ONDXPagePtr(ONDXPage* pRefPage) + : mpPage(pRefPage) + , nPagePos(0) +{ + if (mpPage != nullptr) + mpPage->AddFirstRef(); + if (pRefPage) + nPagePos = pRefPage->GetPagePos(); +} + +ONDXPagePtr::~ONDXPagePtr() +{ + if (mpPage != nullptr) mpPage->ReleaseRef(); +} + +void ONDXPagePtr::Clear() +{ + if (mpPage != nullptr) { + ONDXPage * pRefObj = mpPage; + mpPage = nullptr; + pRefObj->ReleaseRef(); + } +} + +ONDXPagePtr& ONDXPagePtr::operator=(ONDXPagePtr const & rOther) +{ + ONDXPagePtr aTemp(rOther); + *this = std::move(aTemp); + return *this; +} + +ONDXPagePtr& ONDXPagePtr::operator=(ONDXPagePtr && rOther) +{ + if (mpPage != nullptr) { + mpPage->ReleaseRef(); + } + mpPage = rOther.mpPage; + nPagePos = rOther.nPagePos; + rOther.mpPage = nullptr; + return *this; +} + +static sal_uInt32 nValue; + +SvStream& connectivity::dbase::operator >> (SvStream &rStream, ONDXPage& rPage) +{ + rStream.Seek(rPage.GetPagePos() * DINDEX_PAGE_SIZE); + rStream.ReadUInt32( nValue ) >> rPage.aChild; + rPage.nCount = sal_uInt16(nValue); + + for (sal_uInt16 i = 0; i < rPage.nCount; i++) + rPage[i].Read(rStream, rPage.GetIndex()); + return rStream; +} + + +SvStream& connectivity::dbase::WriteONDXPage(SvStream &rStream, const ONDXPage& rPage) +{ + // Page doesn't exist yet + std::size_t nSize = rPage.GetPagePos() + 1; + nSize *= DINDEX_PAGE_SIZE; + if (nSize > rStream.TellEnd()) + { + rStream.SetStreamSize(nSize); + rStream.Seek(rPage.GetPagePos() * DINDEX_PAGE_SIZE); + + char aEmptyData[DINDEX_PAGE_SIZE] = {}; + rStream.WriteBytes(aEmptyData, DINDEX_PAGE_SIZE); + } + rStream.Seek(rPage.GetPagePos() * DINDEX_PAGE_SIZE); + + nValue = rPage.nCount; + rStream.WriteUInt32( nValue ); + WriteONDXPagePtr( rStream, rPage.aChild ); + + sal_uInt16 i = 0; + for (; i < rPage.nCount; i++) + rPage[i].Write(rStream, rPage); + + // check if we have to fill the stream with '\0' + if(i < rPage.rIndex.getHeader().db_maxkeys) + { + std::size_t nTell = rStream.Tell() % DINDEX_PAGE_SIZE; + sal_uInt16 nBufferSize = rStream.GetBufferSize(); + std::size_t nRemainSize = nBufferSize - nTell; + if ( nRemainSize <= nBufferSize ) + { + std::unique_ptr<char[]> pEmptyData( new char[nRemainSize] ); + memset(pEmptyData.get(), 0x00, nRemainSize); + rStream.WriteBytes(pEmptyData.get(), nRemainSize); + rStream.Seek(nTell); + } + } + return rStream; +} + +#if OSL_DEBUG_LEVEL > 1 + +void ONDXPage::PrintPage() +{ + SAL_WARN("connectivity.dbase", "SDB: -----------Page: " << nPagePos << " Parent: " << (HasParent() ? aParent->GetPagePos() : 0) + << " Count: " << nCount << " Child: " << aChild.GetPagePos() << "-----"); + + for (sal_uInt16 i = 0; i < nCount; i++) + { + ONDXNode rNode = (*this)[i]; + ONDXKey& rKey = rNode.GetKey(); + if (!IsLeaf()) + rNode.GetChild(&rIndex, this); + + if (rKey.getValue().isNull()) + { + SAL_WARN("connectivity.dbase", "SDB: [" << rKey.GetRecord() << ",NULL," << rNode.GetChild().GetPagePos() << "]"); + } + else if (rIndex.getHeader().db_keytype) + { + SAL_WARN("connectivity.dbase", "SDB: [" << rKey.GetRecord() << "," << rKey.getValue().getDouble() + << "," << rNode.GetChild().GetPagePos() << "]"); + } + else + { + SAL_WARN("connectivity.dbase", "SDB: [" << rKey.GetRecord() << "," << rKey.getValue().getString() + << "," << rNode.GetChild().GetPagePos() << "]" ); + } + } + SAL_WARN("connectivity.dbase", "SDB: -----------------------------------------------"); + if (!IsLeaf()) + { +#if OSL_DEBUG_LEVEL > 1 + GetChild(&rIndex)->PrintPage(); + for (sal_uInt16 i = 0; i < nCount; i++) + { + ONDXNode rNode = (*this)[i]; + rNode.GetChild(&rIndex,this)->PrintPage(); + } +#endif + } + SAL_WARN("connectivity.dbase", "SDB: ==============================================="); +} +#endif + +bool ONDXPage::IsFull() const +{ + return Count() == rIndex.getHeader().db_maxkeys; +} + + +sal_uInt16 ONDXPage::Search(const ONDXKey& rSearch) +{ + // binary search later + sal_uInt16 i = NODE_NOTFOUND; + while (++i < Count()) + if ((*this)[i].GetKey() == rSearch) + break; + + return (i < Count()) ? i : NODE_NOTFOUND; +} + + +sal_uInt16 ONDXPage::Search(const ONDXPage* pPage) +{ + sal_uInt16 i = NODE_NOTFOUND; + while (++i < Count()) + if (((*this)[i]).GetChild() == pPage) + break; + + // if not found, then we assume, that the page itself points to the page + return (i < Count()) ? i : NODE_NOTFOUND; +} + +// runs recursively +void ONDXPage::SearchAndReplace(const ONDXKey& rSearch, + ONDXKey const & rReplace) +{ + OSL_ENSURE(rSearch != rReplace,"Invalid here:rSearch == rReplace"); + if (rSearch == rReplace) + return; + + sal_uInt16 nPos = NODE_NOTFOUND; + ONDXPage* pPage = this; + + while (pPage) + { + nPos = pPage->Search(rSearch); + if (nPos != NODE_NOTFOUND) + break; + pPage = pPage->aParent; + } + + if (pPage) + { + (*pPage)[nPos].GetKey() = rReplace; + pPage->SetModified(true); + } +} + +ONDXNode& ONDXPage::operator[] (sal_uInt16 nPos) +{ + DBG_ASSERT(nCount > nPos, "incorrect index access"); + return ppNodes[nPos]; +} + + +const ONDXNode& ONDXPage::operator[] (sal_uInt16 nPos) const +{ + DBG_ASSERT(nCount > nPos, "incorrect index access"); + return ppNodes[nPos]; +} + +void ONDXPage::Remove(sal_uInt16 nPos) +{ + DBG_ASSERT(nCount > nPos, "incorrect index access"); + + for (sal_uInt16 i = nPos; i < (nCount-1); i++) + (*this)[i] = (*this)[i+1]; + + nCount--; + bModified = true; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/EApi.cxx b/connectivity/source/drivers/evoab2/EApi.cxx new file mode 100644 index 000000000..12096bdad --- /dev/null +++ b/connectivity/source/drivers/evoab2/EApi.cxx @@ -0,0 +1,186 @@ +/* -*- 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 <rtl/ustring.hxx> +#include <osl/module.hxx> +#define DECLARE_FN_POINTERS 1 +#include "EApi.h" +static const char *eBookLibNames[] = { + "libebook-1.2.so.20", // evolution-data-server 3.33.2+ + "libebook-1.2.so.19", // evolution-data-server 3.24+ + "libebook-1.2.so.16", + "libebook-1.2.so.15", + "libebook-1.2.so.14", // bumped again (evolution-3.6) + "libebook-1.2.so.13", // bumped again (evolution-3.4) + "libebook-1.2.so.12", // bumped again + "libebook-1.2.so.10", // bumped again + "libebook-1.2.so.9", // evolution-2.8 + "libebook-1.2.so.5", // evolution-2.4 and 2.6+ + "libebook-1.2.so.3", // evolution-2.2 + "libebook.so.8" // evolution-2.0 +}; + +typedef void (*SymbolFunc) (); + +#define SYM_MAP(a) { #a, reinterpret_cast<SymbolFunc *>(&a) } + +namespace { + +struct ApiMap +{ + const char *sym_name; + SymbolFunc *ref_value; +}; + +} + +static const ApiMap aCommonApiMap[] = +{ + SYM_MAP( eds_check_version ), + SYM_MAP( e_contact_field_name ), + SYM_MAP( e_contact_get ), + SYM_MAP( e_contact_get_type ), + SYM_MAP( e_contact_field_id ), + SYM_MAP( e_book_new ), + SYM_MAP( e_book_open ), + SYM_MAP( e_book_get_source ), + SYM_MAP( e_book_get_contacts ), + SYM_MAP( e_book_query_field_test ), + SYM_MAP( e_book_query_and ), + SYM_MAP( e_book_query_or ), + SYM_MAP( e_book_query_not ), + SYM_MAP( e_book_query_ref ), + SYM_MAP( e_book_query_unref ), + SYM_MAP( e_book_query_from_string ), + SYM_MAP( e_book_query_to_string ), + SYM_MAP( e_book_query_field_exists ) +}; + +//< 3.6 api +static const ApiMap aOldApiMap[] = +{ + SYM_MAP( e_book_get_addressbooks ), + SYM_MAP( e_book_get_uri ), + SYM_MAP( e_book_authenticate_user ), + SYM_MAP( e_source_group_peek_base_uri), + SYM_MAP( e_source_peek_name ), + SYM_MAP( e_source_get_property ), + SYM_MAP( e_source_list_peek_groups ), + SYM_MAP( e_source_group_peek_sources ) +}; + +//>= 3.6 api +static const ApiMap aNewApiMap[] = +{ + SYM_MAP( e_source_registry_list_sources ), + SYM_MAP( e_source_registry_new_sync ), + SYM_MAP( e_source_has_extension ), + SYM_MAP( e_source_get_extension ), + SYM_MAP( e_source_backend_get_backend_name ), + SYM_MAP( e_source_get_display_name ), + SYM_MAP( e_source_get_uid ), + SYM_MAP( e_source_registry_ref_source), + SYM_MAP( e_client_open_sync ), + SYM_MAP( e_client_get_source ), + SYM_MAP( e_book_client_get_contacts_sync ), + SYM_MAP( e_client_util_free_object_slist ) +}; + +//== indirect read access (3.6 only) +static const ApiMap aClientApiMap36[] = +{ + SYM_MAP( e_book_client_new ) +}; + +//>= direct read access API (>= 3.8) +static const ApiMap aClientApiMap38[] = +{ + SYM_MAP( e_book_client_connect_direct_sync ) +}; + +#undef SYM_MAP + +template<size_t N> static bool +tryLink( osl::Module &rModule, const char *pName, const ApiMap (&pMap)[N]) +{ + for (size_t i = 0; i < N; ++i) + { + SymbolFunc aMethod = reinterpret_cast<SymbolFunc>( + rModule.getFunctionSymbol(OUString::createFromAscii(pMap[i].sym_name))); + if( !aMethod ) + { + fprintf( stderr, "Warning: missing symbol '%s' in '%s'\n", + pMap[ i ].sym_name, pName ); + return false; + } + *pMap[ i ].ref_value = aMethod; + } + return true; +} + +bool EApiInit() +{ + for( guint j = 0; j < G_N_ELEMENTS( eBookLibNames ); j++ ) + { + osl::Module aModule(OUString::createFromAscii(eBookLibNames[j]), SAL_LOADMODULE_DEFAULT); + + if (!aModule.is()) + continue; + + if (tryLink( aModule, eBookLibNames[ j ], aCommonApiMap)) + { + if (eds_check_version( 3, 6, 0 ) != nullptr) + { + if (tryLink( aModule, eBookLibNames[ j ], aOldApiMap)) + { + aModule.release(); + return true; + } + } + else if (tryLink( aModule, eBookLibNames[ j ], aNewApiMap)) + { + if (eds_check_version( 3, 7, 6 ) != nullptr) + { + if (tryLink( aModule, eBookLibNames[ j ], aClientApiMap36)) + { + aModule.release(); + return true; + } + } + else + { + if (tryLink( aModule, eBookLibNames[ j ], aClientApiMap38)) + { + aModule.release(); + return true; + } + } + } + } + } + fprintf( stderr, "Can find no compliant libebook client libraries\n" ); + return false; +} + +ESourceRegistry *get_e_source_registry() +{ + static ESourceRegistry *theInstance = e_source_registry_new_sync(nullptr, nullptr); + return theInstance; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/EApi.h b/connectivity/source/drivers/evoab2/EApi.h new file mode 100644 index 000000000..8c05f95fa --- /dev/null +++ b/connectivity/source/drivers/evoab2/EApi.h @@ -0,0 +1,162 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_EAPI_H +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_EAPI_H +#include <glib-object.h> + +// Initializes the API below, returns false if not available +bool EApiInit(); + +G_BEGIN_DECLS + +// This header defined all the API methods as +// function pointers instead of real functions +// this will all evaporate as it is compiled generating +// no symbol lookups or relocations, but giving code +// clarity. + +// We attempt to define a minimum API that we use: + +// e-contact.h +#ifdef DECLARE_FN_POINTERS +#define EAPI_EXTERN +#else +#define EAPI_EXTERN extern +#endif + + +typedef void EContact; +#define E_CONTACT(a) ((EContact *)(a)) +#define E_TYPE_CONTACT (e_contact_get_type()) +typedef int EContactField; + +EAPI_EXTERN const char *(*e_contact_field_name) ( EContactField field_id); +EAPI_EXTERN gpointer (*e_contact_get) (EContact *contact, EContactField field_id); +EAPI_EXTERN gconstpointer (*e_contact_get_const) (EContact *contact, EContactField field_id); +// e-source.h +typedef void ESource; +#define E_SOURCE(a) ((ESource *)(a)) +EAPI_EXTERN const char *(*e_source_peek_name) (ESource *source); +EAPI_EXTERN const gchar *(*e_source_get_property) (ESource *source, + const gchar *property); + +EAPI_EXTERN GType (*e_contact_get_type) (void); +EAPI_EXTERN EContactField (*e_contact_field_id) (const char *field_name); + +// e-source-list.h +typedef void ESourceList; +EAPI_EXTERN GSList *(*e_source_list_peek_groups) (ESourceList *list); + +// e-source-group.h +typedef void ESourceGroup; +#define E_SOURCE_GROUP(a) ((ESourceGroup *)(a)) + +EAPI_EXTERN GSList *(*e_source_group_peek_sources) (ESourceGroup *group); +EAPI_EXTERN const char *(*e_source_group_peek_base_uri) (ESourceGroup *group); +// e-book.h +typedef enum { + E_BOOK_QUERY_IS, + E_BOOK_QUERY_CONTAINS, + E_BOOK_QUERY_BEGINS_WITH, + E_BOOK_QUERY_ENDS_WITH, +} EBookQueryTest; + +typedef void EBook; +typedef void EBookQuery; + +EAPI_EXTERN EBook *(*e_book_new) (ESource *source, + GError **error); + +EAPI_EXTERN gboolean (*e_book_open) (EBook *book, + gboolean only_if_exists, + GError **error); + +EAPI_EXTERN const char *(*e_book_get_uri) (EBook *book); +EAPI_EXTERN ESource *(*e_book_get_source)(EBook *book); + +EAPI_EXTERN gboolean (*e_book_get_addressbooks) (ESourceList **addressbook_sources, + GError **error); + +EAPI_EXTERN gboolean (*e_book_get_contacts) (EBook *book, + EBookQuery *query, + GList **contacts, + GError **error); + +EAPI_EXTERN gboolean (*e_book_authenticate_user) (EBook *book, + const char *user, + const char *passwd, + const char *auth_method, + GError **error); + +// e-book-query.h +EAPI_EXTERN EBookQuery* (*e_book_query_field_exists) (EContactField field); +EAPI_EXTERN EBookQuery* (*e_book_query_field_test) (EContactField field, + EBookQueryTest test, + const char *value); +EAPI_EXTERN EBookQuery* (*e_book_query_and) (int nqs, EBookQuery **qs, gboolean unref); +EAPI_EXTERN EBookQuery* (*e_book_query_or) (int nqs, EBookQuery **qs, gboolean unref); +EAPI_EXTERN EBookQuery* (*e_book_query_not) (EBookQuery *q, gboolean unref); +EAPI_EXTERN EBookQuery* (*e_book_query_ref) (EBookQuery *q); +EAPI_EXTERN void (*e_book_query_unref) (EBookQuery *q); +EAPI_EXTERN char* (*e_book_query_to_string) (EBookQuery *q); +EAPI_EXTERN EBookQuery* (*e_book_query_from_string) (const char *query_string); + +typedef struct { + char *address_format; /* the two letter country code that + determines the format/meaning of the + following fields */ + char *po; + char *ext; + char *street; + char *locality; + char *region; + char *code; + char *country; +} EContactAddress; + +#define E_SOURCE_EXTENSION_ADDRESS_BOOK "Address Book" +typedef void ESourceRegistry; +typedef void GCancellable; +typedef void ESourceBackend; +typedef void EClient; +typedef EClient EBookClient; +EAPI_EXTERN ESourceRegistry* (*e_source_registry_new_sync) (GCancellable *cancellable, GError **error); +EAPI_EXTERN GList* (*e_source_registry_list_sources) (ESourceRegistry *registry, const gchar *extension_name); +EAPI_EXTERN gboolean (*e_source_has_extension) (ESource *source, const gchar *extension_name); +EAPI_EXTERN gpointer (*e_source_get_extension) (ESource *source, const gchar *extension_name); +EAPI_EXTERN const gchar* (*e_source_backend_get_backend_name) (ESourceBackend *extension); +EAPI_EXTERN const gchar* (*e_source_get_display_name) (ESource *source); +EAPI_EXTERN const gchar* (*eds_check_version) (guint required_major, guint required_minor, guint required_micro); +EAPI_EXTERN const gchar* (*e_source_get_uid) (ESource *source); +EAPI_EXTERN ESource* (*e_source_registry_ref_source) (ESourceRegistry *registry, const gchar *uid); +EAPI_EXTERN EBookClient* (*e_book_client_new) (ESource *source, GError **error); +EAPI_EXTERN EBookClient* (*e_book_client_connect_direct_sync) (ESourceRegistry *registry, ESource *source, GCancellable *cancellable, GError **error); +EAPI_EXTERN gboolean (*e_client_open_sync) (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GError **error); +EAPI_EXTERN ESource* (*e_client_get_source) (EClient *client); +EAPI_EXTERN gboolean (*e_book_client_get_contacts_sync) (EBookClient *client, const gchar *sexp, GSList **contacts, GCancellable *cancellable, GError **error); +EAPI_EXTERN void (*e_client_util_free_object_slist) (GSList *objects); + +ESourceRegistry *get_e_source_registry(); +bool isSourceBackend(ESource *pSource, const char *backendname); + +G_END_DECLS +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NCatalog.cxx b/connectivity/source/drivers/evoab2/NCatalog.cxx new file mode 100644 index 000000000..fb010b8dc --- /dev/null +++ b/connectivity/source/drivers/evoab2/NCatalog.cxx @@ -0,0 +1,87 @@ +/* -*- 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 "NCatalog.hxx" +#include "NConnection.hxx" +#include "NTables.hxx" +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> + + +using namespace connectivity::evoab; +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; + +OEvoabCatalog::OEvoabCatalog(OEvoabConnection* _pCon) : + connectivity::sdbcx::OCatalog(_pCon) + ,m_pConnection(_pCon) +{ +} +void OEvoabCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + Sequence< OUString > aTypes { "TABLE" }; + Reference< XResultSet > xResult = m_xMetaData->getTables( + Any(), "%", "%", aTypes); + + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + OUString aName; + + while(xResult->next()) + { + aName = xRow->getString(3); + aVector.push_back(aName); + } + } + if(m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset( new OEvoabTables(m_xMetaData,*this,m_aMutex,aVector) ); +} +// XTablesSupplier +Reference< XNameAccess > SAL_CALL OEvoabCatalog::getTables( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + try + { + if (!m_pTables) { + refreshTables(); + } + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pTables.get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NCatalog.hxx b/connectivity/source/drivers/evoab2/NCatalog.hxx new file mode 100644 index 000000000..d883d53c2 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NCatalog.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCATALOG_HXX + +#include <sdbcx/VCatalog.hxx> + +namespace connectivity +{ + namespace evoab + { + class OEvoabConnection; + class OEvoabCatalog : public connectivity::sdbcx::OCatalog + { + OEvoabConnection *m_pConnection; + public: + explicit OEvoabCatalog(OEvoabConnection *_pCon); + OEvoabConnection* getConnection() const { return m_pConnection; } + virtual void refreshTables() override; + virtual void refreshViews() override {} + virtual void refreshGroups() override {} + virtual void refreshUsers() override {} + // XTablesSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( + ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NColumns.cxx b/connectivity/source/drivers/evoab2/NColumns.cxx new file mode 100644 index 000000000..378e2af77 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NColumns.cxx @@ -0,0 +1,88 @@ +/* -*- 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 "NColumns.hxx" +#include "NTable.hxx" +#include <connectivity/sdbcx/VColumn.hxx> +#include <com/sun/star/sdbc/XRow.hpp> + +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::comphelper; +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; +using namespace connectivity::evoab; + + +sdbcx::ObjectType OEvoabColumns::createObject(const OUString& _rName) +{ + const Any aCatalog; + const OUString sCatalogName; + const OUString sSchemaName(m_pTable->getSchema()); + const OUString sTableName(m_pTable->getTableName()); + Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns( + aCatalog, + sSchemaName, + sTableName, + _rName); + + sdbcx::ObjectType xRet; + if (xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + + while (xResult->next()) + { + if (xRow->getString(4) == _rName) + { + OColumn* pRet = new OColumn( + _rName, + xRow->getString(6), + xRow->getString(13), + xRow->getString(12), + xRow->getInt(11), + xRow->getInt(7), + xRow->getInt(9), + xRow->getInt(5), + false, + false, + false, + true, + sCatalogName, + sSchemaName, + sTableName); + xRet = pRet; + break; + } + } + } + + return xRet; +} + +void OEvoabColumns::impl_refresh() +{ + m_pTable->refreshColumns(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NColumns.hxx b/connectivity/source/drivers/evoab2/NColumns.hxx new file mode 100644 index 000000000..d3038aaa6 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NColumns.hxx @@ -0,0 +1,50 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCOLUMNS_HXX + +#include "NTable.hxx" +#include <connectivity/sdbcx/VCollection.hxx> + +namespace connectivity +{ + namespace evoab + { + class OEvoabColumns final : public sdbcx::OCollection + { + OEvoabTable* m_pTable; + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + + public: + OEvoabColumns( OEvoabTable* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector + ) : sdbcx::OCollection(*_pTable,true,_rMutex,_rVector), + m_pTable(_pTable) + { } + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NConnection.cxx b/connectivity/source/drivers/evoab2/NConnection.cxx new file mode 100644 index 000000000..d586d6ba2 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NConnection.cxx @@ -0,0 +1,245 @@ +/* -*- 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 "NConnection.hxx" +#include "NDatabaseMetaData.hxx" +#include "NCatalog.hxx" +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include "NPreparedStatement.hxx" +#include "NStatement.hxx" +#include <connectivity/dbexception.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + +using namespace connectivity::evoab; +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::lang; + +OEvoabConnection::OEvoabConnection(OEvoabDriver const & _rDriver) + : m_rDriver(_rDriver) + , m_eSDBCAddressType(SDBCAddress::EVO_LOCAL) +{ +} + +OEvoabConnection::~OEvoabConnection() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if(!isClosed()) { + acquire(); + close(); + } +} + + +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OEvoabConnection, "com.sun.star.sdbc.drivers.evoab.Connection", "com.sun.star.sdbc.Connection") + + +void OEvoabConnection::construct(const OUString& url, const Sequence< PropertyValue >& info) +{ + osl_atomic_increment( &m_refCount ); + SAL_INFO("connectivity.evoab2", "OEvoabConnection::construct()::url = " << url ); + + OUString sPassword; + const char pPwd[] = "password"; + + const PropertyValue *pIter = info.getConstArray(); + const PropertyValue *pEnd = pIter + info.getLength(); + for(;pIter != pEnd;++pIter) + { + if(pIter->Name == pPwd) + { + pIter->Value >>= sPassword; + break; + } + } + + if ( url == "sdbc:address:evolution:groupwise" ) + setSDBCAddressType(SDBCAddress::EVO_GWISE); + else if ( url == "sdbc:address:evolution:ldap" ) + setSDBCAddressType(SDBCAddress::EVO_LDAP); + else + setSDBCAddressType(SDBCAddress::EVO_LOCAL); + setURL(url); + setPassword(OUStringToOString(sPassword,RTL_TEXTENCODING_UTF8)); + osl_atomic_decrement( &m_refCount ); +} + + +OUString SAL_CALL OEvoabConnection::nativeSQL( const OUString& _sSql ) +{ + // when you need to transform SQL92 to you driver specific you can do it here + return _sSql; +} + +Reference< XDatabaseMetaData > SAL_CALL OEvoabConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new OEvoabDatabaseMetaData(this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +css::uno::Reference< XTablesSupplier > OEvoabConnection::createCatalog() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XTablesSupplier > xTab = m_xCatalog; + if(!xTab.is()) + { + OEvoabCatalog *pCat = new OEvoabCatalog(this); + xTab = pCat; + m_xCatalog = xTab; + } + return xTab; +} + +Reference< XStatement > SAL_CALL OEvoabConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + OStatement* pStmt = new OStatement(this); + + Reference< XStatement > xStmt = pStmt; + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return xStmt; +} + +Reference< XPreparedStatement > SAL_CALL OEvoabConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + OEvoabPreparedStatement* pStmt = new OEvoabPreparedStatement( this ); + Reference< XPreparedStatement > xStmt = pStmt; + pStmt->construct( sql ); + + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return xStmt; +} + +Reference< XPreparedStatement > SAL_CALL OEvoabConnection::prepareCall( const OUString& /*sql*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this ); + return nullptr; +} +sal_Bool SAL_CALL OEvoabConnection::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return OConnection_BASE::rBHelper.bDisposed; +} + + +// XCloseable +void SAL_CALL OEvoabConnection::close( ) +{ + { // we just dispose us + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + } + dispose(); +} + + +// XWarningsSupplier +Any SAL_CALL OEvoabConnection::getWarnings( ) +{ + return m_aWarnings.getWarnings(); +} +void SAL_CALL OEvoabConnection::clearWarnings( ) +{ + m_aWarnings.clearWarnings(); +} + + +void OEvoabConnection::disposing() +{ + // we noticed that we should be destroyed in near future so we have to dispose our statements + ::osl::MutexGuard aGuard(m_aMutex); + OConnection_BASE::disposing(); +} + +// -------------------------------- stubbed methods ------------------------------------------------ +void SAL_CALL OEvoabConnection::setAutoCommit( sal_Bool /*autoCommit*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setAutoCommit", *this ); +} +sal_Bool SAL_CALL OEvoabConnection::getAutoCommit( ) +{ + return true; +} +void SAL_CALL OEvoabConnection::commit( ) +{ +} +void SAL_CALL OEvoabConnection::rollback( ) +{ +} +void SAL_CALL OEvoabConnection::setReadOnly( sal_Bool /*readOnly*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setReadOnly", *this ); +} +sal_Bool SAL_CALL OEvoabConnection::isReadOnly( ) +{ + return false; +} +void SAL_CALL OEvoabConnection::setCatalog( const OUString& /*catalog*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setCatalog", *this ); +} + +OUString SAL_CALL OEvoabConnection::getCatalog( ) +{ + return OUString(); +} +void SAL_CALL OEvoabConnection::setTransactionIsolation( sal_Int32 /*level*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTransactionIsolation", *this ); +} + +sal_Int32 SAL_CALL OEvoabConnection::getTransactionIsolation( ) +{ + return TransactionIsolation::NONE; +} + +Reference< css::container::XNameAccess > SAL_CALL OEvoabConnection::getTypeMap( ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this ); + return nullptr; +} +void SAL_CALL OEvoabConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NConnection.hxx b/connectivity/source/drivers/evoab2/NConnection.hxx new file mode 100644 index 000000000..2ba2a8db7 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NConnection.hxx @@ -0,0 +1,112 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCONNECTION_HXX + +#include "NDriver.hxx" +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <connectivity/CommonTools.hxx> +#include <connectivity/warningscontainer.hxx> +#include <TConnection.hxx> +#include <cppuhelper/weakref.hxx> +#include <osl/module.h> +#include "EApi.h" + +namespace connectivity +{ + namespace evoab + { + + namespace SDBCAddress { + typedef enum { + Unknown = 0, + EVO_LOCAL = 1, + EVO_LDAP = 2, + EVO_GWISE = 3 + } sdbc_address_type; + } + + typedef connectivity::OMetaConnection OConnection_BASE; // implements basics and text encoding + + class OEvoabConnection final :public OConnection_BASE + { + private: + const OEvoabDriver& m_rDriver; + SDBCAddress::sdbc_address_type m_eSDBCAddressType; + css::uno::Reference< css::sdbcx::XTablesSupplier > + m_xCatalog; + OString m_aPassword; + ::dbtools::WarningsContainer m_aWarnings; + + virtual ~OEvoabConnection() override; + + public: + explicit OEvoabConnection( OEvoabDriver const & _rDriver ); + /// @throws css::sdbc::SQLException + void construct(const OUString& _rUrl,const css::uno::Sequence< css::beans::PropertyValue >& _rInfo ); + + OString const & getPassword() const { return m_aPassword; } + void setPassword( OString const & aStr ) { m_aPassword = aStr; } + // own methods + const OEvoabDriver& getDriver() const { return m_rDriver; } + + SDBCAddress::sdbc_address_type getSDBCAddressType() const { return m_eSDBCAddressType;} + void setSDBCAddressType(SDBCAddress::sdbc_address_type _eSDBCAddressType) {m_eSDBCAddressType = _eSDBCAddressType;} + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // XConnection + css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog(); + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NDatabaseMetaData.cxx b/connectivity/source/drivers/evoab2/NDatabaseMetaData.cxx new file mode 100644 index 000000000..9eb6f1d34 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NDatabaseMetaData.cxx @@ -0,0 +1,1218 @@ +/* -*- 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 "NDatabaseMetaData.hxx" +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <connectivity/dbexception.hxx> +#include <connectivity/FValue.hxx> +#include <com/sun/star/sdbc/ColumnSearch.hpp> + +#include <cstddef> +#include <string.h> +#include "EApi.h" + +using namespace connectivity::evoab; +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::sdbcx; + +namespace +{ + bool equal(const char *str1, const char *str2) + { + return str1 == nullptr || str2 == nullptr ? str1 == str2 : strcmp(str1, str2) == 0; + } +} + +namespace connectivity::evoab +{ + static sal_Int32 const s_nCOLUMN_SIZE = 256; + static sal_Int32 const s_nDECIMAL_DIGITS = 0; + static sal_Int32 const s_nNULLABLE = 1; + static sal_Int32 const s_nCHAR_OCTET_LENGTH = 65535; + + static ColumnProperty **pFields=nullptr; + static guint nFields = 0; + + static const char *pBlackList[] = + { + "id", + "list-show-addresses", + "address-label-home", + "address-label-work", + "address-label-other" + }; + + const SplitEvoColumns* get_evo_addr() + { + static const SplitEvoColumns evo_addr[] = { + {"addr-line1",DEFAULT_ADDR_LINE1},{"addr-line2",DEFAULT_ADDR_LINE2},{"city",DEFAULT_CITY},{"state",DEFAULT_STATE},{"country",DEFAULT_COUNTRY},{"zip",DEFAULT_ZIP}, + {"work-addr-line1",WORK_ADDR_LINE1},{"work-addr-line2",WORK_ADDR_LINE2},{"work-city",WORK_CITY},{"work-state",WORK_STATE},{"work-country",WORK_COUNTRY},{"work-zip",WORK_ZIP}, + {"home-addr-line1",HOME_ADDR_LINE1},{"home-addr-line2",HOME_ADDR_LINE2},{"home-addr-City",HOME_CITY},{"home-state",HOME_STATE},{"home-country",HOME_COUNTRY},{"home-zip",HOME_ZIP}, + {"other-addr-line1",OTHER_ADDR_LINE1},{"other-addr-line2",OTHER_ADDR_LINE2},{"other-addr-city",OTHER_CITY},{"other-addr-state",OTHER_STATE},{"other-addr-country",OTHER_COUNTRY},{"other-addr-zip",OTHER_ZIP} + }; + return evo_addr; + } + + static void + splitColumn (ColumnProperty **pToBeFields) + { + const SplitEvoColumns* evo_addr( get_evo_addr() ); + for (int i = 0; i < OTHER_ZIP; i++) + { + pToBeFields[nFields] = g_new0(ColumnProperty,1); + pToBeFields[nFields]->bIsSplittedValue = true; + pToBeFields[nFields]->pField = g_param_spec_ref(g_param_spec_string (evo_addr[i].pColumnName,evo_addr[i].pColumnName,"",nullptr,G_PARAM_WRITABLE)); + nFields++; + } + } + + static void + initFields() + { + if( pFields ) + return; + + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if( pFields ) + return; + + guint nProps; + ColumnProperty **pToBeFields; + GParamSpec **pProps; + nFields = 0; + pProps = g_object_class_list_properties + ( static_cast<GObjectClass *>(g_type_class_ref( E_TYPE_CONTACT )), + &nProps ); + pToBeFields = g_new0(ColumnProperty *, (nProps + OTHER_ZIP)/* new column(s)*/ ); + for ( guint i = 0; i < nProps; i++ ) + { + switch (pProps[i]->value_type) + { + case G_TYPE_STRING: + case G_TYPE_BOOLEAN: + { + bool bAdd = true; + const char *pName = g_param_spec_get_name( pProps[i] ); + for (unsigned int j = 0; j < G_N_ELEMENTS( pBlackList ); j++ ) + { + if( !strcmp( pBlackList[j], pName ) ) + { + bAdd = false; + break; + } + } + if( bAdd ) + { + pToBeFields[nFields]= g_new0(ColumnProperty,1); + pToBeFields[nFields]->bIsSplittedValue=false; + pToBeFields[ nFields++ ]->pField = g_param_spec_ref( pProps[i] ); + } + break; + } + default: + break; + } + } + + splitColumn(pToBeFields); + pFields = pToBeFields; + } + + + const ColumnProperty * + getField(guint n) + { + initFields(); + if( n < nFields ) + return pFields[n]; + else + return nullptr; + } + + GType + getGFieldType( guint nCol ) + { + initFields(); + + if ( nCol < nFields ) + return pFields[nCol]->pField->value_type; + return G_TYPE_STRING; + } + + sal_Int32 + getFieldType( guint nCol ) + { + sal_Int32 nType = getGFieldType( nCol ); + return nType == G_TYPE_STRING ? DataType::VARCHAR : DataType::BIT; + } + + guint findEvoabField(const OUString& aColName) + { + guint nRet = guint(-1); + bool bFound = false; + initFields(); + for (guint i=0;(i < nFields) && !bFound;i++) + { + OUString aName = getFieldName(i); + if (aName == aColName) + { + nRet = i; + bFound = true; + } + } + return nRet; + } + + OUString + getFieldTypeName( guint nCol ) + { + switch( getFieldType( nCol ) ) + { + case DataType::BIT: + return "BIT"; + case DataType::VARCHAR: + return "VARCHAR"; + default: + break; + } + return OUString(); + } + + OUString + getFieldName( guint nCol ) + { + const GParamSpec *pSpec = getField( nCol )->pField; + OUString aName; + initFields(); + + if( pSpec ) + { + aName = OStringToOUString( g_param_spec_get_name( const_cast<GParamSpec *>(pSpec) ), + RTL_TEXTENCODING_UTF8 ); + aName = aName.replace( '-', '_' ); + } + return aName; + } + + void + free_column_resources() + { + for (int i=nFields-1;i > 0;i--) + { + if (pFields && pFields[i] ) + { + if (pFields[i]->pField) + g_param_spec_unref(pFields[i]->pField); + g_free(pFields[i]); + } + } + if(pFields) + { + g_free(pFields); + pFields=nullptr; + } + + } + + +} + + +OEvoabDatabaseMetaData::OEvoabDatabaseMetaData(OEvoabConnection* _pCon) + : ::connectivity::ODatabaseMetaDataBase(_pCon, _pCon->getConnectionInfo()) + ,m_pConnection(_pCon) +{ + OSL_ENSURE(m_pConnection,"OEvoabDatabaseMetaData::OEvoabDatabaseMetaData: No connection set!"); +} +OEvoabDatabaseMetaData::~OEvoabDatabaseMetaData() +{ +} + + +ODatabaseMetaDataResultSet::ORows OEvoabDatabaseMetaData::getColumnRows( const OUString& columnNamePattern ) +{ + ODatabaseMetaDataResultSet::ORows aRows; + ODatabaseMetaDataResultSet::ORow aRow(19); + + // **************************************************** + // Some entries in a row never change, so set them now + // **************************************************** + + // Catalog + aRow[1] = new ORowSetValueDecorator(OUString()); + // Schema + aRow[2] = new ORowSetValueDecorator(OUString()); + // COLUMN_SIZE + aRow[7] = new ORowSetValueDecorator(s_nCOLUMN_SIZE); + // BUFFER_LENGTH, not used + aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue(); + // DECIMAL_DIGITS. + aRow[9] = new ORowSetValueDecorator(s_nDECIMAL_DIGITS); + // NUM_PREC_RADIX + aRow[10] = new ORowSetValueDecorator(sal_Int32(10)); + // NULLABLE + aRow[11] = new ORowSetValueDecorator(s_nNULLABLE); + // REMARKS + aRow[12] = ODatabaseMetaDataResultSet::getEmptyValue(); + // COULUMN_DEF, not used + aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue(); + // SQL_DATA_TYPE, not used + aRow[14] = ODatabaseMetaDataResultSet::getEmptyValue(); + // SQL_DATETIME_SUB, not used + aRow[15] = ODatabaseMetaDataResultSet::getEmptyValue(); + // CHAR_OCTET_LENGTH, refer to [5] + aRow[16] = new ORowSetValueDecorator(s_nCHAR_OCTET_LENGTH); + // IS_NULLABLE + aRow[18] = new ORowSetValueDecorator(OUString("YES")); + + + aRow[3] = new ORowSetValueDecorator(OUString("TABLE")); + ::osl::MutexGuard aGuard( m_aMutex ); + + initFields(); + for (sal_Int32 i = 0; i < static_cast<sal_Int32>(nFields); i++) + { + if( match( columnNamePattern, getFieldName( i ), '\0' ) ) + { + aRow[5] = new ORowSetValueDecorator( static_cast<sal_Int16>( getFieldType( i ) ) ); + aRow[6] = new ORowSetValueDecorator( getFieldTypeName( i ) ); + + // COLUMN_NAME + aRow[4] = new ORowSetValueDecorator( getFieldName( i ) ); + // ORDINAL_POSITION + aRow[17] = new ORowSetValueDecorator( i ); + aRows.push_back( aRow ); + } + } + + return aRows ; +} + +OUString OEvoabDatabaseMetaData::impl_getCatalogSeparator_throw( ) +{ + return OUString(); +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxRowSize( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxCatalogNameLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxCharLiteralLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnNameLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInIndex( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxCursorNameLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxConnections( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInTable( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 OEvoabDatabaseMetaData::impl_getMaxStatements_throw( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxTableNameLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 OEvoabDatabaseMetaData::impl_getMaxTablesInSelect_throw( ) +{ + // We only support a single table + return 1; +} + + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( ) +{ + return false; +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxIndexLength( ) +{ + return 0;// 0 means no limit +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsNonNullableColumns( ) +{ + return false; +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getCatalogTerm( ) +{ + return OUString(); +} + +OUString OEvoabDatabaseMetaData::impl_getIdentifierQuoteString_throw( ) +{ + // normally this is " + return "\""; +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getExtraNameCharacters( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_isCatalogAtStart_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsPositionedDelete( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsPositionedUpdate( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 /*level*/ ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsANSI92FullSQL( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + return true; // should be supported at least +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOuterJoins( ) +{ + return false; +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxStatementLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxProcedureNameLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxSchemaNameLength( ) +{ + return 0;// 0 means no limit +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::allProceduresAreCallable( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsStoredProcedures( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSelectForUpdate( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::allTablesAreSelectable( ) +{ + // We allow you to select from any table. + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::isReadOnly( ) +{ + // For now definitely read-only, no support for update/delete + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::usesLocalFiles( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::usesLocalFilePerTable( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsTypeConversion( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullPlusNonNullIsNull( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsColumnAliasing( ) +{ + // todo add Support for this. + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsTableCorrelationNames( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsConvert( sal_Int32 /*fromType*/, sal_Int32 /*toType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsGroupBy( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsGroupByUnrelated( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsMultipleTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsMultipleResultSets( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsLikeEscapeClause( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsOrderByUnrelated( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsUnion( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsUnionAll( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + return false; +} + +bool OEvoabDatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( ) +{ + // Any case may be used + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullsAreSortedAtEnd( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullsAreSortedAtStart( ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullsAreSortedHigh( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::nullsAreSortedLow( ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSubqueriesInExists( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSubqueriesInIns( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + return false; +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getURL( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return m_pConnection->getURL(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getUserName( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getDriverName( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getDriverVersion() +{ + return "1"; +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getDatabaseProductVersion( ) +{ + return "0"; +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getDatabaseProductName( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getProcedureTerm( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getSchemaTerm( ) +{ + return OUString(); +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getDriverMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getDefaultTransactionIsolation( ) +{ + return TransactionIsolation::NONE; +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getDriverMinorVersion( ) +{ + return 0; +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getSQLKeywords( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getSearchStringEscape( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getStringFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getTimeDateFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getSystemFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabDatabaseMetaData::getNumericFunctions( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsCoreSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsFullOuterJoins( ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return false; +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxColumnsInSelect( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL OEvoabDatabaseMetaData::getMaxUserNameLength( ) +{ + return 0;// 0 means no limit +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsResultSetType( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsResultSetConcurrency( sal_Int32 /*setType*/, sal_Int32 /*concurrency*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::ownDeletesAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::ownInsertsAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::othersDeletesAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::othersInsertsAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::updatesAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::deletesAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::insertsAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabDatabaseMetaData::supportsBatchUpdates( ) +{ + return false; +} + +// here follow all methods which return a resultset +// the first methods is an example implementation how to use this resultset +// of course you could implement it on your and you should do this because +// the general way is more memory expensive + +Reference< XResultSet > SAL_CALL OEvoabDatabaseMetaData::getTableTypes( ) +{ + /* Don't need to change as evoab driver supports only table */ + + // there exists no possibility to get table types so we have to check + static const OUStringLiteral sTableTypes[] = + { + "TABLE" // Currently we only support a 'TABLE' nothing more complex + }; + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTableTypes); + Reference< XResultSet > xRef = pResult; + + // here we fill the rows which should be visible when ask for data from the resultset returned here + ODatabaseMetaDataResultSet::ORows aRows; + for(std::size_t i=0;i < SAL_N_ELEMENTS(sTableTypes);++i) + { + ODatabaseMetaDataResultSet::ORow aRow; + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(OUString(sTableTypes[i]))); + + // bound row + aRows.push_back(aRow); + } + // here we set the rows at the resultset + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > OEvoabDatabaseMetaData::impl_getTypeInfo_throw( ) +{ + /* + * Return the proper type information required by evo driver + */ + + ODatabaseMetaDataResultSet* pResultSet = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo); + + Reference< XResultSet > xResultSet = pResultSet; + static ODatabaseMetaDataResultSet::ORows aRows = []() + { + ODatabaseMetaDataResultSet::ORows tmp; + ODatabaseMetaDataResultSet::ORow aRow; + aRow.reserve(19); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(OUString("VARCHAR"))); + aRow.push_back(new ORowSetValueDecorator(DataType::VARCHAR)); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(s_nCHAR_OCTET_LENGTH))); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + // aRow.push_back(new ORowSetValueDecorator((sal_Int32)ColumnValue::NULLABLE)); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(ColumnSearch::FULL))); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(10))); + + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::VARCHAR); + aRow[3] = new ORowSetValueDecorator(sal_Int32(65535)); + tmp.push_back(aRow); + return tmp; + }(); + pResultSet->setRows(aRows); + return xResultSet; +} + +Reference< XResultSet > SAL_CALL OEvoabDatabaseMetaData::getColumns( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*tableNamePattern*/, + const OUString& columnNamePattern ) +{ + // this returns an empty resultset where the column-names are already set + // in special the metadata of the resultset already returns the right columns + ODatabaseMetaDataResultSet* pResultSet = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumns ); + Reference< XResultSet > xResultSet = pResultSet; + pResultSet->setRows( getColumnRows( columnNamePattern ) ); + return xResultSet; +} + + +bool isSourceBackend(ESource *pSource, const char *backendname) +{ + if (!pSource || !e_source_has_extension (pSource, E_SOURCE_EXTENSION_ADDRESS_BOOK)) + return false; + + gpointer extension = e_source_get_extension (pSource, E_SOURCE_EXTENSION_ADDRESS_BOOK); + return extension && equal(e_source_backend_get_backend_name (extension), backendname); +} + +Reference< XResultSet > SAL_CALL OEvoabDatabaseMetaData::getTables( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, + const OUString& /*tableNamePattern*/, const Sequence< OUString >& types ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes); + Reference< XResultSet > xRef = pResult; + + // check if any type is given + // when no types are given then we have to return all tables e.g. TABLE + + const OUString aTable("TABLE"); + + bool bTableFound = true; + sal_Int32 nLength = types.getLength(); + if(nLength) + { + bTableFound = false; + + const OUString* pBegin = types.getConstArray(); + const OUString* pEnd = pBegin + nLength; + for(;pBegin != pEnd;++pBegin) + { + if(*pBegin == aTable) + { + bTableFound = true; + break; + } + } + } + if(!bTableFound) + return xRef; + + ODatabaseMetaDataResultSet::ORows aRows; + + if (eds_check_version(3, 6, 0) == nullptr) + { + GList *pSources = e_source_registry_list_sources(get_e_source_registry(), E_SOURCE_EXTENSION_ADDRESS_BOOK); + + for (GList* liter = pSources; liter; liter = liter->next) + { + ESource *pSource = E_SOURCE (liter->data); + bool can = false; + switch (m_pConnection->getSDBCAddressType()) + { + case SDBCAddress::EVO_GWISE: + can = isSourceBackend( pSource, "groupwise"); // not supported in evo/eds 3.6.x+, somehow + break; + case SDBCAddress::EVO_LOCAL: + can = isSourceBackend( pSource, "local"); + break; + case SDBCAddress::EVO_LDAP: + can = isSourceBackend( pSource, "ldap"); + break; + case SDBCAddress::Unknown: + can = true; + break; + } + if (!can) + continue; + + OUString aHumanName = OStringToOUString( e_source_get_display_name( pSource ), + RTL_TEXTENCODING_UTF8 ); + OUString aUID = OStringToOUString( e_source_get_uid( pSource ), + RTL_TEXTENCODING_UTF8 ); + ODatabaseMetaDataResultSet::ORow aRow{ + ORowSetValueDecoratorRef(), + ORowSetValueDecoratorRef(), + ORowSetValueDecoratorRef(), + new ORowSetValueDecorator(aHumanName), //tablename + new ORowSetValueDecorator(aTable), + new ORowSetValueDecorator(aUID)}; //comment + //I'd prefer to swap the comment and the human name and + //just use e_source_registry_ref_source(get_e_source_registry(), aUID); + //in open book rather than search for the name again + aRows.push_back(aRow); + } + + g_list_foreach (pSources, reinterpret_cast<GFunc>(g_object_unref), nullptr); + g_list_free (pSources); + } + else + { + ESourceList *pSourceList; + if( !e_book_get_addressbooks (&pSourceList, nullptr) ) + pSourceList = nullptr; + + GSList *g; + for( g = e_source_list_peek_groups( pSourceList ); g; g = g->next) + { + GSList *s; + const char *p = e_source_group_peek_base_uri(E_SOURCE_GROUP(g->data)); + + switch (m_pConnection->getSDBCAddressType()) { + case SDBCAddress::EVO_GWISE: + if ( !strncmp( "groupwise://", p, 11 )) + break; + else + continue; + case SDBCAddress::EVO_LOCAL: + if ( !strncmp( "file://", p, 6 ) || + !strncmp( "local://", p, 6 ) ) + break; + else + continue; + case SDBCAddress::EVO_LDAP: + if ( !strncmp( "ldap://", p, 6 )) + break; + else + continue; + case SDBCAddress::Unknown: + break; + } + for (s = e_source_group_peek_sources (E_SOURCE_GROUP (g->data)); s; s = s->next) + { + ESource *pSource = E_SOURCE (s->data); + + OUString aName = OStringToOUString( e_source_peek_name( pSource ), + RTL_TEXTENCODING_UTF8 ); + + ODatabaseMetaDataResultSet::ORow aRow{ + ORowSetValueDecoratorRef(), + ORowSetValueDecoratorRef(), + ORowSetValueDecoratorRef(), + new ORowSetValueDecorator(aName), + new ORowSetValueDecorator(aTable), + ODatabaseMetaDataResultSet::getEmptyValue()}; + aRows.push_back(aRow); + } + } + } + + pResult->setRows(aRows); + + return xRef; +} + +Reference< XResultSet > SAL_CALL OEvoabDatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XDatabaseMetaDaza::getUDTs", *this ); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NDatabaseMetaData.hxx b/connectivity/source/drivers/evoab2/NDatabaseMetaData.hxx new file mode 100644 index 000000000..61a9449e6 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NDatabaseMetaData.hxx @@ -0,0 +1,221 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NDATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NDATABASEMETADATA_HXX + +#include "NConnection.hxx" +#include <TDatabaseMetaDataBase.hxx> +#include <FDatabaseMetaDataResultSet.hxx> + + +namespace connectivity +{ + namespace evoab + { + + //************ Class: OEvoabDatabaseMetaData + + typedef struct{ + gboolean bIsSplittedValue; + GParamSpec *pField; + }ColumnProperty; + + typedef enum { + DEFAULT_ADDR_LINE1=1,DEFAULT_ADDR_LINE2,DEFAULT_CITY,DEFAULT_STATE,DEFAULT_COUNTRY,DEFAULT_ZIP, + WORK_ADDR_LINE1,WORK_ADDR_LINE2,WORK_CITY,WORK_STATE,WORK_COUNTRY,WORK_ZIP, + HOME_ADDR_LINE1,HOME_ADDR_LINE2,HOME_CITY,HOME_STATE,HOME_COUNTRY,HOME_ZIP, + OTHER_ADDR_LINE1,OTHER_ADDR_LINE2,OTHER_CITY,OTHER_STATE,OTHER_COUNTRY,OTHER_ZIP + }ColumnNumber; + + typedef struct { + const gchar *pColumnName; + ColumnNumber value; + }SplitEvoColumns; + + const SplitEvoColumns* get_evo_addr(); + + const ColumnProperty *getField(guint n); + GType getGFieldType(guint nCol) ; + sal_Int32 getFieldType(guint nCol) ; + OUString getFieldTypeName(guint nCol) ; + OUString getFieldName(guint nCol) ; + guint findEvoabField(const OUString& aColName); + + void free_column_resources(); + + class OEvoabDatabaseMetaData : public ODatabaseMetaDataBase + { + OEvoabConnection* m_pConnection; + + ODatabaseMetaDataResultSet::ORows getColumnRows( const OUString& columnNamePattern ); + + protected: + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + // cached database information + virtual OUString impl_getIdentifierQuoteString_throw( ) override; + virtual bool impl_isCatalogAtStart_throw( ) override; + virtual OUString impl_getCatalogSeparator_throw( ) override; + virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override; + virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ; + virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override; + virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ; + virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override ; + virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override; + virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override; + virtual sal_Int32 impl_getMaxStatements_throw( ) override; + virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override; + virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override; + + virtual ~OEvoabDatabaseMetaData() override; + public: + explicit OEvoabDatabaseMetaData(OEvoabConnection* _pCon); + + // as I mentioned before this interface is really BIG + // XDatabaseMetaData + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NDATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NDriver.cxx b/connectivity/source/drivers/evoab2/NDriver.cxx new file mode 100644 index 000000000..d7f4e376a --- /dev/null +++ b/connectivity/source/drivers/evoab2/NDriver.cxx @@ -0,0 +1,166 @@ +/* -*- 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 "NDriver.hxx" +#include "NConnection.hxx" +#include <com/sun/star/lang/DisposedException.hpp> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + +using namespace osl; +using namespace connectivity::evoab; +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::lang; +using namespace ::com::sun::star::ucb; + + +OEvoabDriver::OEvoabDriver(const Reference< XMultiServiceFactory >& _rxFactory) : + ODriver_BASE( m_aMutex ), m_xFactory( _rxFactory ) +{ +} + +OEvoabDriver::~OEvoabDriver() +{ +} + +void OEvoabDriver::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + // when driver will be destroyed so all our connections have to be destroyed as well + for (const auto& rxConnection : m_xConnections) + { + Reference< XComponent > xComp(rxConnection.get(), UNO_QUERY); + if (xComp.is()) + { + try + { + xComp->dispose(); + } + catch (const css::lang::DisposedException&) + { + xComp.clear(); + } + } + } + m_xConnections.clear(); + connectivity::OWeakRefArray().swap(m_xConnections); // this really clears + + ODriver_BASE::disposing(); +} + +// static ServiceInfo + +OUString OEvoabDriver::getImplementationName_Static( ) +{ + return EVOAB_DRIVER_IMPL_NAME; + // this name is referenced in the configuration and in the evoab.xml + // Please take care when changing it. +} + + +Sequence< OUString > OEvoabDriver::getSupportedServiceNames_Static( ) +{ + // which service is supported + // for more information @see com.sun.star.sdbc.Driver + Sequence<OUString> aSNS { "com.sun.star.sdbc.Driver" }; + return aSNS; +} + +OUString SAL_CALL OEvoabDriver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL OEvoabDriver::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > SAL_CALL OEvoabDriver::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + + +css::uno::Reference< css::uno::XInterface > connectivity::evoab::OEvoabDriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory) +{ + return *(new OEvoabDriver(_rxFactory)); +} + +Reference< XConnection > SAL_CALL OEvoabDriver::connect( const OUString& url, const Sequence< PropertyValue >& info ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (ODriver_BASE::rBHelper.bDisposed) + throw DisposedException(); + + if ( ! acceptsURL(url) ) + return nullptr; + + OEvoabConnection* pCon = new OEvoabConnection( *this ); + pCon->construct(url,info); + Reference< XConnection > xCon = pCon; + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + + return xCon; +} + +sal_Bool SAL_CALL OEvoabDriver::acceptsURL( const OUString& url ) +{ + return acceptsURL_Stat(url); +} + + +Sequence< DriverPropertyInfo > SAL_CALL OEvoabDriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) +{ + if ( ! acceptsURL(url) ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } // if ( ! acceptsURL(url) ) + + // if you have something special to say return it here :-) + return Sequence< DriverPropertyInfo >(); +} + + +sal_Int32 SAL_CALL OEvoabDriver::getMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL OEvoabDriver::getMinorVersion( ) +{ + return 0; +} + +bool OEvoabDriver::acceptsURL_Stat( const OUString& url ) +{ + return ( url == "sdbc:address:evolution:local" || url == "sdbc:address:evolution:groupwise" || url == "sdbc:address:evolution:ldap" ) && EApiInit(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NDriver.hxx b/connectivity/source/drivers/evoab2/NDriver.hxx new file mode 100644 index 000000000..a2c12a87f --- /dev/null +++ b/connectivity/source/drivers/evoab2/NDriver.hxx @@ -0,0 +1,87 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NDRIVER_HXX + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/compbase.hxx> +#include <connectivity/CommonTools.hxx> + +#define EVOAB_DRIVER_IMPL_NAME "com.sun.star.comp.sdbc.evoab.OEvoabDriver" + +namespace connectivity +{ + namespace evoab + { + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > OEvoabDriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver, + css::lang::XServiceInfo > ODriver_BASE; + + + class OEvoabDriver final : public ODriver_BASE + { + ::osl::Mutex m_aMutex; + connectivity::OWeakRefArray m_xConnections; + css::uno::Reference< css::lang::XMultiServiceFactory > m_xFactory; + + public: + explicit OEvoabDriver(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + virtual ~OEvoabDriver() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XInterface + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + + public: + css::uno::Reference< css::uno::XComponentContext > + getComponentContext( ) const { return comphelper::getComponentContext( m_xFactory ); } + + // static methods + static bool acceptsURL_Stat( const OUString& url ); + }; + } + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NDRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NPreparedStatement.cxx b/connectivity/source/drivers/evoab2/NPreparedStatement.cxx new file mode 100644 index 000000000..57981e95e --- /dev/null +++ b/connectivity/source/drivers/evoab2/NPreparedStatement.cxx @@ -0,0 +1,319 @@ +/* -*- 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 "NPreparedStatement.hxx" +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <tools/diagnose_ex.h> + +#include <strings.hrc> + +using namespace connectivity::evoab; +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::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +IMPLEMENT_SERVICE_INFO(OEvoabPreparedStatement,"com.sun.star.sdbcx.evoab.PreparedStatement","com.sun.star.sdbc.PreparedStatement"); + + +OEvoabPreparedStatement::OEvoabPreparedStatement( OEvoabConnection* _pConnection ) + :OCommonStatement(_pConnection) + ,m_sSqlStatement() + ,m_xMetaData() +{ +} + + +void OEvoabPreparedStatement::construct( const OUString& _sql ) +{ + m_sSqlStatement = _sql; + + m_aQueryData = impl_getEBookQuery_throw( m_sSqlStatement ); + ENSURE_OR_THROW( m_aQueryData.getQuery(), "no EBookQuery" ); + ENSURE_OR_THROW( m_aQueryData.xSelectColumns.is(), "no SelectColumn" ); + + // create our meta data + OEvoabResultSetMetaData* pMeta = new OEvoabResultSetMetaData( m_aQueryData.sTable ); + m_xMetaData = pMeta; + pMeta->setEvoabFields( m_aQueryData.xSelectColumns ); +} + + +OEvoabPreparedStatement::~OEvoabPreparedStatement() +{ +} + + +void SAL_CALL OEvoabPreparedStatement::acquire() throw() +{ + OCommonStatement::acquire(); +} + + +void SAL_CALL OEvoabPreparedStatement::release() throw() +{ + OCommonStatement::release(); +} + + +Any SAL_CALL OEvoabPreparedStatement::queryInterface( const Type & rType ) +{ + Any aRet = OCommonStatement::queryInterface(rType); + if(!aRet.hasValue()) + aRet = OPreparedStatement_BASE::queryInterface(rType); + return aRet; +} + +Sequence< Type > SAL_CALL OEvoabPreparedStatement::getTypes( ) +{ + return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OCommonStatement::getTypes()); +} + + +Reference< XResultSetMetaData > SAL_CALL OEvoabPreparedStatement::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + // the meta data should have been created at construction time + ENSURE_OR_THROW( m_xMetaData.is(), "internal error: no meta data" ); + return m_xMetaData; +} + + +void SAL_CALL OEvoabPreparedStatement::close( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + free_column_resources(); + // Reset last warning message + try { + clearWarnings (); + OCommonStatement::close(); + } + catch (SQLException &) { + // If we get an error, ignore + } + +} + + +sal_Bool SAL_CALL OEvoabPreparedStatement::execute( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + Reference< XResultSet> xRS = impl_executeQuery_throw( m_aQueryData ); + return xRS.is(); +} + + +sal_Int32 SAL_CALL OEvoabPreparedStatement::executeUpdate( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "XStatement::executeUpdate", *this ); + return 0; +} + + +void SAL_CALL OEvoabPreparedStatement::setString( sal_Int32 /*parameterIndex*/, const OUString& /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setString", *this ); +} + + +Reference< XConnection > SAL_CALL OEvoabPreparedStatement::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + return impl_getConnection(); +} + + +Reference< XResultSet > SAL_CALL OEvoabPreparedStatement::executeQuery( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + return impl_executeQuery_throw( m_aQueryData ); +} + + +void SAL_CALL OEvoabPreparedStatement::setBoolean( sal_Int32 /*parameterIndex*/, sal_Bool /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setBoolean", *this ); + +} + +void SAL_CALL OEvoabPreparedStatement::setByte( sal_Int32 /*parameterIndex*/, sal_Int8 /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setByte", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setDate( sal_Int32 /*parameterIndex*/, const Date& /*aData*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setDate", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setTime( sal_Int32 /*parameterIndex*/, const css::util::Time& /*aVal*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setTime", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setTimestamp( sal_Int32 /*parameterIndex*/, const DateTime& /*aVal*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setTimestamp", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setDouble( sal_Int32 /*parameterIndex*/, double /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setDouble", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setFloat( sal_Int32 /*parameterIndex*/, float /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setFloat", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setInt( sal_Int32 /*parameterIndex*/, sal_Int32 /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setInt", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setLong( sal_Int32 /*parameterIndex*/, sal_Int64 /*aVal*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setLong", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setNull( sal_Int32 /*parameterIndex*/, sal_Int32 /*sqlType*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setNull", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setClob", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setBlob", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setArray", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setRef", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setObjectWithInfo( sal_Int32 /*parameterIndex*/, const Any& /*x*/, sal_Int32 /*sqlType*/, sal_Int32 /*scale*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setObjectWithInfo", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setObjectNull( sal_Int32 /*parameterIndex*/, sal_Int32 /*sqlType*/, const OUString& /*typeName*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setObjectNull", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) +{ + if(!::dbtools::implSetObject(this,parameterIndex,x)) + { + const OUString sError( getOwnConnection()->getResources().getResourceStringWithSubstitution( + STR_UNKNOWN_PARA_TYPE, + "$position$", OUString::number(parameterIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } +} + + +void SAL_CALL OEvoabPreparedStatement::setShort( sal_Int32 /*parameterIndex*/, sal_Int16 /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setShort", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setBytes( sal_Int32 /*parameterIndex*/, const Sequence< sal_Int8 >& /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setBytes", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setCharacterStream( sal_Int32 /*parameterIndex*/, const Reference< XInputStream >& /*x*/, sal_Int32 /*length*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setCharacterStream", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::setBinaryStream( sal_Int32 /*parameterIndex*/, const Reference< XInputStream >& /*x*/, sal_Int32 /*length*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setBinaryStream", *this ); +} + + +void SAL_CALL OEvoabPreparedStatement::clearParameters( ) +{ +} + +Reference< XResultSet > SAL_CALL OEvoabPreparedStatement::getResultSet( ) +{ + return nullptr; +} + +sal_Int32 SAL_CALL OEvoabPreparedStatement::getUpdateCount( ) +{ + return 0; +} + +sal_Bool SAL_CALL OEvoabPreparedStatement::getMoreResults( ) +{ + return false; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NPreparedStatement.hxx b/connectivity/source/drivers/evoab2/NPreparedStatement.hxx new file mode 100644 index 000000000..20d5790ca --- /dev/null +++ b/connectivity/source/drivers/evoab2/NPreparedStatement.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NPREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NPREPAREDSTATEMENT_HXX + +#include "NStatement.hxx" +#include "NConnection.hxx" +#include "NDatabaseMetaData.hxx" +#include "NResultSet.hxx" +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <cppuhelper/implbase5.hxx> + +namespace connectivity +{ + namespace evoab + { + + typedef ::cppu::ImplHelper5< css::sdbc::XPreparedStatement, + css::sdbc::XParameters, + css::sdbc::XResultSetMetaDataSupplier, + css::sdbc::XMultipleResults, + css::lang::XServiceInfo> OPreparedStatement_BASE; + + class OEvoabPreparedStatement final:public OCommonStatement + ,public OPreparedStatement_BASE + { + // our SQL statement + OUString m_sSqlStatement; + // the EBookQuery we're working with + QueryData m_aQueryData; + // our meta data + css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData; + + virtual ~OEvoabPreparedStatement() override; + + public: + explicit OEvoabPreparedStatement( OEvoabConnection* _pConnection ); + + void construct( const OUString& _sql ); + + private: + DECLARE_SERVICE_INFO(); + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + virtual sal_Bool SAL_CALL execute( ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NPREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NResultSet.cxx b/connectivity/source/drivers/evoab2/NResultSet.cxx new file mode 100644 index 000000000..77d53939c --- /dev/null +++ b/connectivity/source/drivers/evoab2/NResultSet.cxx @@ -0,0 +1,1142 @@ +/* -*- 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 "NDatabaseMetaData.hxx" +#include "NConnection.hxx" +#include "NResultSet.hxx" +#include <propertyids.hxx> +#include <strings.hrc> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> + +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/sqlerror.hxx> +#include <rtl/string.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/syslocale.hxx> +#include <unotools/intlwrapper.hxx> +#include <unotools/collatorwrapper.hxx> + +#include <cstring> + +namespace connectivity::evoab { + +using namespace ::comphelper; +using namespace com::sun::star; +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +namespace ErrorCondition = ::com::sun::star::sdb::ErrorCondition; + + +OUString SAL_CALL OEvoabResultSet::getImplementationName( ) +{ + return "com.sun.star.sdbcx.evoab.ResultSet"; +} + + Sequence< OUString > SAL_CALL OEvoabResultSet::getSupportedServiceNames( ) +{ + Sequence< OUString > aSupported { "com.sun.star.sdbc.ResultSet" }; + return aSupported; +} + +sal_Bool SAL_CALL OEvoabResultSet::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +struct ComparisonData +{ + const SortDescriptor& rSortOrder; + IntlWrapper aIntlWrapper; + + ComparisonData(const SortDescriptor& _rSortOrder) + : rSortOrder(_rSortOrder) + , aIntlWrapper(SvtSysLocale().GetUILanguageTag()) + { + } +}; + +static OUString +valueToOUString( GValue& _rValue ) +{ + const char *pStr = g_value_get_string( &_rValue ); + OString aStr( pStr ? pStr : "" ); + OUString sResult( OStringToOUString( aStr, RTL_TEXTENCODING_UTF8 ) ); + g_value_unset( &_rValue ); + return sResult; +} + +static bool +valueToBool( GValue& _rValue ) +{ + bool bResult = g_value_get_boolean( &_rValue ); + g_value_unset( &_rValue ); + return bResult; +} + +static int +whichAddress(int value) +{ + int fieldEnum; + switch (value) + { + case HOME_ADDR_LINE1: + case HOME_ADDR_LINE2: + case HOME_CITY: + case HOME_STATE: + case HOME_COUNTRY: + case HOME_ZIP: + fieldEnum = e_contact_field_id("address_home"); + break; + + case WORK_ADDR_LINE1: + case WORK_ADDR_LINE2: + case WORK_CITY: + case WORK_STATE: + case WORK_COUNTRY: + case WORK_ZIP: + fieldEnum = e_contact_field_id("address_work"); + break; + + case OTHER_ADDR_LINE1: + case OTHER_ADDR_LINE2: + case OTHER_CITY: + case OTHER_STATE: + case OTHER_COUNTRY: + case OTHER_ZIP: + fieldEnum = e_contact_field_id("address_other"); + break; + + default: fieldEnum = e_contact_field_id("address_home"); + } + return fieldEnum; +} + +/* +* This function decides the default column values based on the first field of EContactAddress. +* The search order is Work->Home->other(defaults). +*/ +static EContactAddress * +getDefaultContactAddress( EContact *pContact,int *value ) +{ + EContactAddress *ec = static_cast<EContactAddress *>(e_contact_get(pContact,whichAddress(WORK_ADDR_LINE1))); + if ( ec && (ec->street[0]!='\0') ) + { + *value= *value +WORK_ADDR_LINE1 -1; + return ec; + } + else + { + ec = static_cast<EContactAddress *>(e_contact_get(pContact,whichAddress(HOME_ADDR_LINE1))); + if ( ec && (ec->street[0]!='\0') ) + { + *value=*value+HOME_ADDR_LINE1-1; + return ec; + } + } + + *value=*value+OTHER_ADDR_LINE1-1; + return static_cast<EContactAddress *>(e_contact_get(pContact,whichAddress(OTHER_ADDR_LINE1))); +} + +static EContactAddress* +getContactAddress( EContact *pContact, int * address_enum ) +{ + EContactAddress *ec = nullptr; + switch (*address_enum) { + + case DEFAULT_ADDR_LINE1: + case DEFAULT_ADDR_LINE2: + case DEFAULT_CITY: + case DEFAULT_STATE: + case DEFAULT_COUNTRY: + case DEFAULT_ZIP: + ec = getDefaultContactAddress(pContact,address_enum);break; + default: + ec = static_cast<EContactAddress *>(e_contact_get(pContact,whichAddress(*address_enum))); + } + return ec; +} + +static bool +handleSplitAddress( EContact *pContact,GValue *pStackValue, int value ) +{ + EContactAddress *ec = getContactAddress(pContact,&value) ; + + if (ec==nullptr) + return true; + + switch (value) { + case WORK_ADDR_LINE1: + g_value_set_string(pStackValue,ec->street ); break; + case WORK_ADDR_LINE2: + g_value_set_string(pStackValue,ec->po ); break; + case WORK_CITY: + g_value_set_string(pStackValue,ec->locality ); break; + case WORK_STATE: + g_value_set_string(pStackValue,ec->region ); break; + case WORK_COUNTRY: + g_value_set_string(pStackValue,ec->country ); break; + case WORK_ZIP: + g_value_set_string(pStackValue,ec->code ); break; + + case HOME_ADDR_LINE1: + g_value_set_string(pStackValue,ec->street ); break; + case HOME_ADDR_LINE2: + g_value_set_string(pStackValue,ec->po ); break; + case HOME_CITY: + g_value_set_string(pStackValue,ec->locality ); break; + case HOME_STATE: + g_value_set_string(pStackValue,ec->region ); break; + case HOME_COUNTRY: + g_value_set_string(pStackValue,ec->country ); break; + case HOME_ZIP: + g_value_set_string(pStackValue,ec->code ); break; + + case OTHER_ADDR_LINE1: + g_value_set_string(pStackValue,ec->street ); break; + case OTHER_ADDR_LINE2: + g_value_set_string(pStackValue,ec->po ); break; + case OTHER_CITY: + g_value_set_string(pStackValue,ec->locality ); break; + case OTHER_STATE: + g_value_set_string(pStackValue,ec->region ); break; + case OTHER_COUNTRY: + g_value_set_string(pStackValue,ec->country ); break; + case OTHER_ZIP: + g_value_set_string(pStackValue,ec->code ); break; + + } + + return false; +} + +static bool +getValue( EContact* pContact, sal_Int32 nColumnNum, GType nType, GValue* pStackValue, bool& _out_rWasNull ) +{ + const ColumnProperty * pSpecs = evoab::getField( nColumnNum ); + if ( !pSpecs ) + return false; + + GParamSpec* pSpec = pSpecs->pField; + bool bIsSplittedColumn = pSpecs->bIsSplittedValue; + + _out_rWasNull = true; + if ( !pSpec || !pContact) + return false; + + if ( G_PARAM_SPEC_VALUE_TYPE (pSpec) != nType ) + { + SAL_WARN("connectivity.evoab2", "Wrong type (0x" << std::hex << static_cast<int>(G_PARAM_SPEC_VALUE_TYPE(pSpec)) << ") (0x" + << std::hex << static_cast<int>(nType) << ") " << (pSpec->name ? pSpec->name : "<noname>")); + return false; + } + + g_value_init( pStackValue, nType ); + if ( bIsSplittedColumn ) + { + const SplitEvoColumns* evo_addr( get_evo_addr() ); + for (int i=0;i<OTHER_ZIP;i++) + { + if (0 == strcmp (g_param_spec_get_name (pSpec), evo_addr[i].pColumnName)) + { + _out_rWasNull = handleSplitAddress( pContact, pStackValue, evo_addr[i].value ); + return true; + } + } + } + else + { + g_object_get_property( G_OBJECT (pContact), + g_param_spec_get_name (pSpec), + pStackValue ); + if ( G_VALUE_TYPE( pStackValue ) != nType ) + { + SAL_WARN("connectivity.evoab2", "Fetched type mismatch" ); + g_value_unset( pStackValue ); + return false; + } + } + _out_rWasNull = false; + return true; +} + +extern "C" { + +static int CompareContacts( gconstpointer _lhs, gconstpointer _rhs, gpointer _userData ) +{ + EContact* lhs = const_cast< gpointer >( _lhs ); + EContact* rhs = const_cast< gpointer >( _rhs ); + + GValue aLhsValue = { 0, { { 0 } } }; + GValue aRhsValue = { 0, { { 0 } } }; + bool bLhsNull = true; + bool bRhsNull = true; + + OUString sLhs, sRhs; + bool bLhs(false), bRhs(false); + + const ComparisonData& rCompData = *static_cast< const ComparisonData* >( _userData ); + for ( const auto& sortCol : rCompData.rSortOrder ) + { + sal_Int32 nField = sortCol.nField; + GType eFieldType = evoab::getGFieldType( nField ); + + bool success = getValue( lhs, nField, eFieldType, &aLhsValue, bLhsNull ) + && getValue( rhs, nField, eFieldType, &aRhsValue, bRhsNull ); + OSL_ENSURE( success, "CompareContacts: could not retrieve both values!" ); + if ( !success ) + return 0; + + if ( bLhsNull && !bRhsNull ) + return -1; + if ( !bLhsNull && bRhsNull ) + return 1; + if ( bLhsNull && bRhsNull ) + continue; + + if ( eFieldType == G_TYPE_STRING ) + { + sLhs = valueToOUString( aLhsValue ); + sRhs = valueToOUString( aRhsValue ); + sal_Int32 nCompResult = rCompData.aIntlWrapper.getCaseCollator()->compareString( sLhs, sRhs ); + if ( nCompResult != 0 ) + return nCompResult; + continue; + } + + bLhs = valueToBool( aLhsValue ); + bRhs = valueToBool( aRhsValue ); + if ( bLhs && !bRhs ) + return -1; + if ( !bLhs && bRhs ) + return 1; + continue; + } + + return 0; +} + +} + +OString OEvoabVersionHelper::getUserName( EBook *pBook ) +{ + OString aName; + if( isLDAP( pBook ) ) + aName = e_source_get_property( e_book_get_source( pBook ), "binddn" ); + else + aName = e_source_get_property( e_book_get_source( pBook ), "user" ); + return aName; +} + +namespace { + +bool isBookBackend( EBookClient *pBook, const char *backendname) +{ + if (!pBook) + return false; + ESource *pSource = e_client_get_source (reinterpret_cast<EClient *>(pBook)); + return isSourceBackend(pSource, backendname); +} + +class OEvoabVersion36Helper : public OEvoabVersionHelper +{ +private: + GSList *m_pContacts; +public: + OEvoabVersion36Helper() + : m_pContacts(nullptr) + { + } + + virtual ~OEvoabVersion36Helper() override + { + freeContacts(); + } + + virtual EBook* openBook(const char *abname) override + { + //It would be better if here we had id to begin with, see + //NDatabaseMetaData.cxx + const char *id = nullptr; + GList *pSources = e_source_registry_list_sources(get_e_source_registry(), E_SOURCE_EXTENSION_ADDRESS_BOOK); + for (GList* liter = pSources; liter; liter = liter->next) + { + ESource *pSource = E_SOURCE (liter->data); + + if (strcmp(abname, e_source_get_display_name( pSource )) == 0) + { + id = e_source_get_uid( pSource ); + break; + } + } + g_list_foreach (pSources, reinterpret_cast<GFunc>(g_object_unref), nullptr); + g_list_free (pSources); + if (!id) + return nullptr; + + ESource *pSource = e_source_registry_ref_source(get_e_source_registry(), id); + EBookClient *pBook = pSource ? createClient (pSource) : nullptr; + if (pBook && !e_client_open_sync (pBook, true, nullptr, nullptr)) + { + g_object_unref (G_OBJECT (pBook)); + pBook = nullptr; + } + if (pSource) + g_object_unref (pSource); + return pBook; + } + + virtual bool isLDAP( EBook *pBook ) override + { + return isBookBackend(pBook, "ldap"); + } + + virtual bool isLocal( EBook *pBook ) override + { + return isBookBackend(pBook, "local"); + } + + virtual void freeContacts() override final + { + e_client_util_free_object_slist(m_pContacts); + m_pContacts = nullptr; + } + + virtual void executeQuery (EBook* pBook, EBookQuery* pQuery, OString &/*rPassword*/) override + { + freeContacts(); + char *sexp = e_book_query_to_string( pQuery ); + e_book_client_get_contacts_sync( pBook, sexp, &m_pContacts, nullptr, nullptr ); + g_free (sexp); + } + + virtual EContact *getContact(sal_Int32 nIndex) override + { + gpointer pData = g_slist_nth_data (m_pContacts, nIndex); + return pData ? E_CONTACT (pData) : nullptr; + } + + virtual sal_Int32 getNumContacts() override + { + return g_slist_length( m_pContacts ); + } + + virtual bool hasContacts() override + { + return m_pContacts != nullptr; + } + + virtual void sortContacts( const ComparisonData& _rCompData ) override + { + OSL_ENSURE( !_rCompData.rSortOrder.empty(), "sortContacts: no need to call this without any sort order!" ); + ENSURE_OR_THROW( _rCompData.aIntlWrapper.getCaseCollator(), "no collator for comparing strings" ); + + m_pContacts = g_slist_sort_with_data( m_pContacts, &CompareContacts, + const_cast< gpointer >( static_cast< gconstpointer >( &_rCompData ) ) ); + } + +protected: + virtual EBookClient * createClient( ESource *pSource ) + { + return e_book_client_new (pSource, nullptr); + } +}; + +class OEvoabVersion38Helper : public OEvoabVersion36Helper +{ +protected: + virtual EBookClient * createClient( ESource *pSource ) override + { + return e_book_client_connect_direct_sync (get_e_source_registry (), pSource, nullptr, nullptr); + } +}; + +ESource * findSource( const char *id ) +{ + ESourceList *pSourceList = nullptr; + + g_return_val_if_fail (id != nullptr, nullptr); + + if (!e_book_get_addressbooks (&pSourceList, nullptr)) + pSourceList = nullptr; + + for ( GSList *g = e_source_list_peek_groups (pSourceList); g; g = g->next) + { + for (GSList *s = e_source_group_peek_sources (E_SOURCE_GROUP (g->data)); s; s = s->next) + { + ESource *pSource = E_SOURCE (s->data); + if (!strcmp (e_source_peek_name (pSource), id)) + return pSource; + } + } + return nullptr; +} + +bool isAuthRequired( EBook *pBook ) +{ + return e_source_get_property( e_book_get_source( pBook ), + "auth" ) != nullptr; +} + +class OEvoabVersion35Helper : public OEvoabVersionHelper +{ +private: + GList *m_pContacts; + +public: + OEvoabVersion35Helper() + : m_pContacts(nullptr) + { + } + + virtual ~OEvoabVersion35Helper() override + { + freeContacts(); + } + + virtual EBook* openBook(const char *abname) override + { + ESource *pSource = findSource (abname); + EBook *pBook = pSource ? e_book_new (pSource, nullptr) : nullptr; + if (pBook && !e_book_open (pBook, true, nullptr)) + { + g_object_unref (G_OBJECT (pBook)); + pBook = nullptr; + } + return pBook; + } + + virtual bool isLDAP( EBook *pBook ) override + { + return pBook && !strncmp( "ldap://", e_book_get_uri( pBook ), 6 ); + } + + virtual bool isLocal( EBook *pBook ) override + { + return pBook && ( !strncmp( "file://", e_book_get_uri( pBook ), 6 ) || + !strncmp( "local:", e_book_get_uri( pBook ), 6 ) ); + } + + virtual void freeContacts() override final + { + g_list_free(m_pContacts); + m_pContacts = nullptr; + } + + virtual void executeQuery (EBook* pBook, EBookQuery* pQuery, OString &rPassword) override + { + freeContacts(); + + ESource *pSource = e_book_get_source( pBook ); + bool bAuthSuccess = true; + + if( isAuthRequired( pBook ) ) + { + OString aUser( getUserName( pBook ) ); + const char *pAuth = e_source_get_property( pSource, "auth" ); + bAuthSuccess = e_book_authenticate_user( pBook, aUser.getStr(), rPassword.getStr(), pAuth, nullptr ); + } + + if (bAuthSuccess) + e_book_get_contacts( pBook, pQuery, &m_pContacts, nullptr ); + } + + virtual EContact *getContact(sal_Int32 nIndex) override + { + gpointer pData = g_list_nth_data (m_pContacts, nIndex); + return pData ? E_CONTACT (pData) : nullptr; + } + + virtual sal_Int32 getNumContacts() override + { + return g_list_length( m_pContacts ); + } + + virtual bool hasContacts() override + { + return m_pContacts != nullptr; + } + + virtual void sortContacts( const ComparisonData& _rCompData ) override + { + OSL_ENSURE( !_rCompData.rSortOrder.empty(), "sortContacts: no need to call this without any sort order!" ); + ENSURE_OR_THROW( _rCompData.aIntlWrapper.getCaseCollator(), "no collator for comparing strings" ); + + m_pContacts = g_list_sort_with_data( m_pContacts, &CompareContacts, + const_cast< gpointer >( static_cast< gconstpointer >( &_rCompData ) ) ); + } +}; + +} + +OEvoabResultSet::OEvoabResultSet( OCommonStatement* pStmt, OEvoabConnection *pConnection ) + :OResultSet_BASE(m_aMutex) + ,::comphelper::OPropertyContainer( OResultSet_BASE::rBHelper ) + ,m_pStatement(pStmt) + ,m_pConnection(pConnection) + ,m_bWasNull(true) + ,m_nFetchSize(0) + ,m_nResultSetType(ResultSetType::SCROLL_INSENSITIVE) + ,m_nFetchDirection(FetchDirection::FORWARD) + ,m_nResultSetConcurrency(ResultSetConcurrency::READ_ONLY) + ,m_nIndex(-1) + ,m_nLength(0) +{ + if (eds_check_version( 3, 7, 6 ) == nullptr) + m_pVersionHelper = std::make_unique<OEvoabVersion38Helper>(); + else if (eds_check_version( 3, 6, 0 ) == nullptr) + m_pVersionHelper = std::make_unique<OEvoabVersion36Helper>(); + else + m_pVersionHelper = std::make_unique<OEvoabVersion35Helper>(); + + #define REGISTER_PROP( id, member ) \ + registerProperty( \ + OMetaConnection::getPropMap().getNameByIndex( id ), \ + id, \ + PropertyAttribute::READONLY, \ + &member, \ + cppu::UnoType<decltype(member)>::get() \ + ); + + REGISTER_PROP( PROPERTY_ID_FETCHSIZE, m_nFetchSize ); + REGISTER_PROP( PROPERTY_ID_RESULTSETTYPE, m_nResultSetType ); + REGISTER_PROP( PROPERTY_ID_FETCHDIRECTION, m_nFetchDirection ); + REGISTER_PROP( PROPERTY_ID_RESULTSETCONCURRENCY, m_nResultSetConcurrency ); +} + +OEvoabResultSet::~OEvoabResultSet() +{} + +void OEvoabResultSet::construct( const QueryData& _rData ) +{ + ENSURE_OR_THROW( _rData.getQuery(), "internal error: no EBookQuery" ); + + EBook *pBook = m_pVersionHelper->openBook(OUStringToOString(_rData.sTable, RTL_TEXTENCODING_UTF8).getStr()); + if ( !pBook ) + m_pConnection->throwGenericSQLException( STR_CANNOT_OPEN_BOOK, *this ); + + m_pVersionHelper->freeContacts(); + bool bExecuteQuery = true; + switch ( _rData.eFilterType ) + { + case eFilterNone: + if ( !m_pVersionHelper->isLocal( pBook ) ) + { + SQLError aErrorFactory; + SQLException aAsException = aErrorFactory.getSQLException( ErrorCondition::DATA_CANNOT_SELECT_UNFILTERED, *this ); + m_aWarnings.appendWarning( SQLWarning( + aAsException.Message, + aAsException.Context, + aAsException.SQLState, + aAsException.ErrorCode, + aAsException.NextException + ) ); + bExecuteQuery = false; + } + break; + case eFilterAlwaysFalse: + bExecuteQuery = false; + break; + case eFilterOther: + bExecuteQuery = true; + break; + } + if ( bExecuteQuery ) + { + OString aPassword = m_pConnection->getPassword(); + m_pVersionHelper->executeQuery(pBook, _rData.getQuery(), aPassword); + m_pConnection->setPassword( aPassword ); + + if ( m_pVersionHelper->hasContacts() && !_rData.aSortOrder.empty() ) + { + ComparisonData aCompData(_rData.aSortOrder); + m_pVersionHelper->sortContacts(aCompData); + } + } + m_nLength = m_pVersionHelper->getNumContacts(); + SAL_INFO("connectivity.evoab2", "Query return " << m_nLength << " records"); + m_nIndex = -1; + + // create our meta data (need the EBookQuery for this) + m_xMetaData = new OEvoabResultSetMetaData( _rData.sTable ); + + m_xMetaData->setEvoabFields( _rData.xSelectColumns ); +} + + +void OEvoabResultSet::disposing() +{ + ::comphelper::OPropertyContainer::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + m_pVersionHelper.reset(); + m_pStatement = nullptr; + m_xMetaData.clear(); +} + +Any SAL_CALL OEvoabResultSet::queryInterface( const Type & rType ) +{ + Any aRet = ::comphelper::OPropertyContainer::queryInterface(rType); + if(!aRet.hasValue()) + aRet = OResultSet_BASE::queryInterface(rType); + return aRet; +} + +Sequence< Type > SAL_CALL OEvoabResultSet::getTypes( ) +{ + return ::comphelper::concatSequences( + OResultSet_BASE::getTypes(), + getBaseTypes() + ); +} + + +// XRow Interface + +/** + * getString: + * @nColumnNum: The column index from the table. + * + * If the equivalent NResultSetMetaData.cxx marks the columntype of + * nColumnNum as DataType::VARCHAR this accessor is used. + */ +OUString SAL_CALL OEvoabResultSet::getString( sal_Int32 nColumnNum ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + OUString aResult; + if ( m_xMetaData.is()) + { + sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(nColumnNum); + GValue aValue = { 0, { { 0 } } }; + if ( getValue( getCur(), nFieldNumber, G_TYPE_STRING, &aValue, m_bWasNull ) ) + aResult = valueToOUString( aValue ); + } + return aResult; +} + +sal_Bool SAL_CALL OEvoabResultSet::getBoolean( sal_Int32 nColumnNum ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + bool bResult = false; + + if ( m_xMetaData.is()) + { + sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(nColumnNum); + GValue aValue = { 0, { { 0 } } }; + if ( getValue( getCur(), nFieldNumber, G_TYPE_BOOLEAN, &aValue, m_bWasNull ) ) + bResult = valueToBool( aValue ); + } + return bResult; +} + +sal_Int64 SAL_CALL OEvoabResultSet::getLong( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getLong", *this ); + return sal_Int64(); +} + +Reference< XArray > SAL_CALL OEvoabResultSet::getArray( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this ); + return nullptr; +} + +Reference< XClob > SAL_CALL OEvoabResultSet::getClob( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this ); + return nullptr; +} + +Reference< XBlob > SAL_CALL OEvoabResultSet::getBlob( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this ); + return nullptr; +} + +Reference< XRef > SAL_CALL OEvoabResultSet::getRef( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this ); + return nullptr; +} + +Any SAL_CALL OEvoabResultSet::getObject( sal_Int32 /*nColumnNum*/, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getObject", *this ); + return Any(); +} + +sal_Int16 SAL_CALL OEvoabResultSet::getShort( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getShort", *this ); + return 0; +} + +css::util::Time SAL_CALL OEvoabResultSet::getTime( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getTime", *this ); + return css::util::Time(); +} + +util::DateTime SAL_CALL OEvoabResultSet::getTimestamp( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getTimestamp", *this ); + return css::util::DateTime(); +} + +Reference< XInputStream > SAL_CALL OEvoabResultSet::getBinaryStream( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this ); + return nullptr; +} + +Reference< XInputStream > SAL_CALL OEvoabResultSet::getCharacterStream( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getCharacterStream", *this ); + return nullptr; +} + +sal_Int8 SAL_CALL OEvoabResultSet::getByte( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getByte", *this ); + return 0; +} + +Sequence< sal_Int8 > SAL_CALL OEvoabResultSet::getBytes( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBytes", *this ); + return Sequence< sal_Int8 >(); +} + +css::util::Date SAL_CALL OEvoabResultSet::getDate( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getDate", *this ); + return css::util::Date(); +} + +double SAL_CALL OEvoabResultSet::getDouble( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getDouble", *this ); + return 0; +} + +float SAL_CALL OEvoabResultSet::getFloat( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getFloat", *this ); + return 0; +} + +sal_Int32 SAL_CALL OEvoabResultSet::getInt( sal_Int32 /*nColumnNum*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getInt", *this ); + return 0; +} +// XRow Interface Ends + + +// XResultSetMetaDataSupplier Interface +Reference< XResultSetMetaData > SAL_CALL OEvoabResultSet::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // the meta data should have been created at construction time + ENSURE_OR_THROW( m_xMetaData.is(), "internal error: no meta data" ); + return m_xMetaData.get(); +} +// XResultSetMetaDataSupplier Interface Ends + + +// XResultSet Interface +sal_Bool SAL_CALL OEvoabResultSet::next( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + if (m_nIndex+1 < m_nLength) { + ++m_nIndex ; + return true; + } + else + return false; +} + +sal_Bool SAL_CALL OEvoabResultSet::wasNull( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + +sal_Bool SAL_CALL OEvoabResultSet::isBeforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nIndex < 0; +} + +sal_Int32 SAL_CALL OEvoabResultSet::getRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nIndex; +} + +sal_Bool SAL_CALL OEvoabResultSet::isAfterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nIndex >= m_nLength; +} + +sal_Bool SAL_CALL OEvoabResultSet::isFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nIndex == 0; +} + +sal_Bool SAL_CALL OEvoabResultSet::isLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nIndex == m_nLength - 1; +} + +void SAL_CALL OEvoabResultSet::beforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_nIndex = -1; +} + +void SAL_CALL OEvoabResultSet::afterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_nIndex = m_nLength; +} + + +sal_Bool SAL_CALL OEvoabResultSet::first( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_nIndex = 0; + return true; +} + + +sal_Bool SAL_CALL OEvoabResultSet::last( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_nIndex = m_nLength - 1; + return true; +} + +sal_Bool SAL_CALL OEvoabResultSet::absolute( sal_Int32 row ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + if (row < m_nLength) { + m_nIndex = row; + return true; + } + else + return false; +} + +sal_Bool SAL_CALL OEvoabResultSet::relative( sal_Int32 row ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if ((m_nIndex+row) < m_nLength) { + m_nIndex += row; + return true; + } + else + return false; +} + +sal_Bool SAL_CALL OEvoabResultSet::previous( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if(m_nIndex > 0) { + m_nIndex--; + return true; + } + else + return false; +} + +Reference< XInterface > SAL_CALL OEvoabResultSet::getStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + css::uno::WeakReferenceHelper aStatement(static_cast<OWeakObject*>(m_pStatement)); + return aStatement.get(); +} + + +sal_Bool SAL_CALL OEvoabResultSet::rowDeleted( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OEvoabResultSet::rowInserted( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OEvoabResultSet::rowUpdated( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +void SAL_CALL OEvoabResultSet::refreshRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); +} +//XResult Interface ends + +// XCancellable + +void SAL_CALL OEvoabResultSet::cancel( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); +} + +//XCloseable +void SAL_CALL OEvoabResultSet::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + } + dispose(); +} + +// XWarningsSupplier + +void SAL_CALL OEvoabResultSet::clearWarnings( ) +{ + m_aWarnings.clearWarnings(); +} + +Any SAL_CALL OEvoabResultSet::getWarnings( ) +{ + return m_aWarnings.getWarnings(); +} + +//XColumnLocate Interface +sal_Int32 SAL_CALL OEvoabResultSet::findColumn( const OUString& columnName ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // find the first column with the name columnName + 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 ); + assert(false); + return 0; // Never reached +} + +//XColumnLocate interface ends + + +::cppu::IPropertyArrayHelper* OEvoabResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +::cppu::IPropertyArrayHelper & OEvoabResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +void SAL_CALL OEvoabResultSet::acquire() throw() +{ + OResultSet_BASE::acquire(); +} + +void SAL_CALL OEvoabResultSet::release() throw() +{ + OResultSet_BASE::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL +OEvoabResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + + +} // connectivity::evoab + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NResultSet.hxx b/connectivity/source/drivers/evoab2/NResultSet.hxx new file mode 100644 index 000000000..40b0027cf --- /dev/null +++ b/connectivity/source/drivers/evoab2/NResultSet.hxx @@ -0,0 +1,187 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NRESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NRESULTSET_HXX + +#include <memory> + +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <cppuhelper/compbase.hxx> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/propertycontainer.hxx> +#include <connectivity/CommonTools.hxx> +#include <connectivity/FValue.hxx> +#include <connectivity/warningscontainer.hxx> +#include "NStatement.hxx" +#include "NResultSetMetaData.hxx" + +namespace connectivity +{ + namespace evoab + { + struct ComparisonData; + + class OEvoabVersionHelper + { + public: + virtual EBook* openBook(const char *abname) = 0; + virtual void executeQuery (EBook* pBook, EBookQuery* pQuery, OString &rPassword) = 0; + virtual void freeContacts() = 0; + virtual bool isLDAP( EBook *pBook ) = 0; + virtual bool isLocal( EBook *pBook ) = 0; + virtual EContact *getContact(sal_Int32 nIndex) = 0; + virtual sal_Int32 getNumContacts() = 0; + virtual bool hasContacts() = 0; + virtual void sortContacts( const ComparisonData& _rCompData ) = 0; + OString getUserName( EBook *pBook ); + virtual ~OEvoabVersionHelper() {} + }; + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet + , css::sdbc::XRow + , css::sdbc::XResultSetMetaDataSupplier + , css::util::XCancellable + , css::sdbc::XWarningsSupplier + , css::sdbc::XCloseable + , css::sdbc::XColumnLocate + , css::lang::XServiceInfo + > OResultSet_BASE; + + + class OEvoabResultSet final : public cppu::BaseMutex + ,public OResultSet_BASE + ,public ::comphelper::OPropertyContainer + ,public ::comphelper::OPropertyArrayUsageHelper<OEvoabResultSet> + { + private: + std::unique_ptr<OEvoabVersionHelper> m_pVersionHelper; + + OCommonStatement* m_pStatement; + OEvoabConnection* m_pConnection; + rtl::Reference<OEvoabResultSetMetaData> m_xMetaData; + ::dbtools::WarningsContainer m_aWarnings; + + bool m_bWasNull; + // <properties> + sal_Int32 m_nFetchSize; + sal_Int32 m_nResultSetType; + sal_Int32 m_nFetchDirection; + sal_Int32 m_nResultSetConcurrency; + // </properties> + + // Data & iteration + sal_Int32 m_nIndex; + sal_Int32 m_nLength; + EContact *getCur() + { + return m_pVersionHelper->getContact(m_nIndex); + } + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // you can't delete objects of this type + virtual ~OEvoabResultSet() override; + public: + DECLARE_SERVICE_INFO(); + + OEvoabResultSet( OCommonStatement *pStmt, OEvoabConnection *pConnection ); + void construct( const QueryData& _rData ); + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NResultSetMetaData.cxx b/connectivity/source/drivers/evoab2/NResultSetMetaData.cxx new file mode 100644 index 000000000..4982cc455 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NResultSetMetaData.cxx @@ -0,0 +1,183 @@ +/* -*- 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 "NResultSetMetaData.hxx" +#include "NDatabaseMetaData.hxx" +#include <connectivity/dbexception.hxx> +#include <strings.hrc> + +using namespace connectivity::evoab; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; + +OEvoabResultSetMetaData::OEvoabResultSetMetaData(const OUString& _aTableName) + : m_aTableName(_aTableName), + m_aEvoabFields() +{ + +} + +OEvoabResultSetMetaData::~OEvoabResultSetMetaData() +{ +} + +void OEvoabResultSetMetaData::setEvoabFields(const ::rtl::Reference<connectivity::OSQLColumns> &xColumns) +{ + static const char aName[] = "Name"; + + for (const auto& rxColumn : *xColumns) + { + OUString aFieldName; + + rxColumn->getPropertyValue(aName) >>= aFieldName; + guint nFieldNumber = findEvoabField(aFieldName); + if (nFieldNumber == guint(-1)) + { + connectivity::SharedResources aResource; + const OUString sError( aResource.getResourceStringWithSubstitution( + STR_INVALID_COLUMNNAME, + "$columnname$", aFieldName + ) ); + ::dbtools::throwGenericSQLException( sError, *this ); + } + m_aEvoabFields.push_back(nFieldNumber); + } +} + + +sal_Int32 SAL_CALL OEvoabResultSetMetaData::getColumnDisplaySize( sal_Int32 /*nColumnNum*/ ) +{ + return 50; +} + +sal_Int32 SAL_CALL OEvoabResultSetMetaData::getColumnType( sal_Int32 nColumnNum ) +{ + sal_uInt32 nField = m_aEvoabFields[nColumnNum - 1]; + return evoab::getFieldType (nField); +} + +sal_Int32 SAL_CALL OEvoabResultSetMetaData::getColumnCount( ) +{ + return m_aEvoabFields.size(); +} + +sal_Bool SAL_CALL OEvoabResultSetMetaData::isCaseSensitive( sal_Int32 /*nColumnNum*/ ) +{ + return true; +} + +OUString SAL_CALL OEvoabResultSetMetaData::getSchemaName( sal_Int32 /*nColumnNum*/ ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabResultSetMetaData::getColumnName( sal_Int32 nColumnNum ) +{ + sal_uInt32 nField = m_aEvoabFields[nColumnNum - 1]; + return evoab::getFieldName( nField ); +} + +OUString SAL_CALL OEvoabResultSetMetaData::getColumnTypeName( sal_Int32 nColumnNum ) +{ + sal_uInt32 nField = m_aEvoabFields[nColumnNum - 1]; + return evoab::getFieldTypeName( nField ); +} + +OUString SAL_CALL OEvoabResultSetMetaData::getColumnLabel( sal_Int32 nColumnNum ) +{ + sal_uInt32 nField = m_aEvoabFields[nColumnNum - 1]; + const ColumnProperty *pSpecs = getField(nField); + GParamSpec *pSpec = pSpecs->pField; + OUString aLabel; + + if( pSpec ) + aLabel = OStringToOUString( g_param_spec_get_nick( pSpec ), + RTL_TEXTENCODING_UTF8 ); + return aLabel; +} + +OUString SAL_CALL OEvoabResultSetMetaData::getColumnServiceName( sal_Int32 /*nColumnNum*/ ) +{ + return OUString(); +} + +OUString SAL_CALL OEvoabResultSetMetaData::getTableName( sal_Int32 /*nColumnNum*/ ) +{ + return m_aTableName;//OUString("TABLE"); +} + +OUString SAL_CALL OEvoabResultSetMetaData::getCatalogName( sal_Int32 /*nColumnNum*/ ) +{ + return OUString(); +} + + +sal_Bool SAL_CALL OEvoabResultSetMetaData::isCurrency( sal_Int32 /*nColumnNum*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabResultSetMetaData::isAutoIncrement( sal_Int32 /*nColumnNum*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabResultSetMetaData::isSigned( sal_Int32 /*nColumnNum*/ ) +{ + return false; +} + +sal_Int32 SAL_CALL OEvoabResultSetMetaData::getPrecision( sal_Int32 /*nColumnNum*/ ) +{ + return 0; +} + +sal_Int32 SAL_CALL OEvoabResultSetMetaData::getScale( sal_Int32 /*nColumnNum*/ ) +{ + return 0; +} + +sal_Int32 SAL_CALL OEvoabResultSetMetaData::isNullable( sal_Int32 /*nColumnNum*/ ) +{ + return 0; +} + +sal_Bool SAL_CALL OEvoabResultSetMetaData::isSearchable( sal_Int32 /*nColumnNum*/ ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabResultSetMetaData::isReadOnly( sal_Int32 /*nColumnNum*/ ) +{ + return true; +} + +sal_Bool SAL_CALL OEvoabResultSetMetaData::isDefinitelyWritable( sal_Int32 /*nColumnNum*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OEvoabResultSetMetaData::isWritable( sal_Int32 /*nColumnNum*/ ) +{ + return false; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NResultSetMetaData.hxx b/connectivity/source/drivers/evoab2/NResultSetMetaData.hxx new file mode 100644 index 000000000..9c309aadd --- /dev/null +++ b/connectivity/source/drivers/evoab2/NResultSetMetaData.hxx @@ -0,0 +1,81 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NRESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NRESULTSETMETADATA_HXX + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include "NConnection.hxx" +#include <rtl/ref.hxx> +#include <com/sun/star/connection/XConnection.hpp> +namespace connectivity +{ + namespace evoab + { + + //************ Class: ResultSetMetaData + + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE; + + class OEvoabResultSetMetaData : public OResultSetMetaData_BASE + { + OUString m_aTableName; + std::vector<sal_Int32> m_aEvoabFields; + + protected: + virtual ~OEvoabResultSetMetaData() override; + public: + explicit OEvoabResultSetMetaData(const OUString& _aTableName); + /// @throws css::sdbc::SQLException + void setEvoabFields(const ::rtl::Reference<connectivity::OSQLColumns> &xColumns); + sal_uInt32 fieldAtColumn(sal_Int32 columnIndex) const + { return m_aEvoabFields[columnIndex - 1]; } + /// Avoid ambiguous cast error from the compiler. + operator css::uno::Reference< css::sdbc::XResultSetMetaData > () throw() + { return this; } + + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NRESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NServices.cxx b/connectivity/source/drivers/evoab2/NServices.cxx new file mode 100644 index 000000000..0fc8f8d07 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NServices.cxx @@ -0,0 +1,108 @@ +/* -*- 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 "NDriver.hxx" +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <osl/diagnose.h> + +using namespace connectivity::evoab; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(const css::uno::Exception&) + { + OSL_FAIL("Service Creation Exception"); + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* evoab2_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + OEvoabDriver::getImplementationName_Static(), + OEvoabDriver::getSupportedServiceNames_Static(), + OEvoabDriver_CreateInstance, ::cppu::createSingleFactory) + ; + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NStatement.cxx b/connectivity/source/drivers/evoab2/NStatement.cxx new file mode 100644 index 000000000..1616f9fb1 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NStatement.cxx @@ -0,0 +1,632 @@ +/* -*- 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 <osl/diagnose.h> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <propertyids.hxx> +#include "NStatement.hxx" +#include "NConnection.hxx" +#include "NDatabaseMetaData.hxx" +#include "NResultSet.hxx" +#include <sqlbison.hxx> +#include <strings.hrc> +#include <connectivity/dbexception.hxx> +#include <tools/diagnose_ex.h> + +namespace connectivity::evoab { + + +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +namespace { + +EBookQuery * createTrue() +{ // Not the world's most efficient unconditional true but ... + return e_book_query_from_string("(exists \"full_name\")"); +} + +EBookQuery * createTest( const OUString &aColumnName, + EBookQueryTest eTest, + const OUString &aMatch ) +{ + OString sMatch = OUStringToOString( aMatch, RTL_TEXTENCODING_UTF8 ); + OString sColumnName = OUStringToOString( aColumnName, RTL_TEXTENCODING_UTF8 ); + + return e_book_query_field_test( e_contact_field_id( sColumnName.getStr() ), + eTest, sMatch.getStr() ); +} + +} + +OCommonStatement::OCommonStatement(OEvoabConnection* _pConnection) + : OCommonStatement_IBase(m_aMutex) + , ::comphelper::OPropertyContainer(OCommonStatement_IBase::rBHelper) + , m_xResultSet(nullptr) + , m_xConnection(_pConnection) + , m_aParser(_pConnection->getDriver().getComponentContext()) + , m_aSQLIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser ) + , m_pParseTree(nullptr) + , m_nMaxFieldSize(0) + , m_nMaxRows(0) + , m_nQueryTimeOut(0) + , m_nFetchSize(0) + , m_nResultSetType(ResultSetType::FORWARD_ONLY) + , m_nFetchDirection(FetchDirection::FORWARD) + , m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE) + , m_bEscapeProcessing(true) +{ +#define REGISTER_PROP( id, member ) \ + registerProperty( \ + OMetaConnection::getPropMap().getNameByIndex( id ), \ + id, \ + 0, \ + &member, \ + cppu::UnoType<decltype(member)>::get() \ + ); + + REGISTER_PROP( PROPERTY_ID_CURSORNAME, m_aCursorName ); + REGISTER_PROP( PROPERTY_ID_MAXFIELDSIZE, m_nMaxFieldSize ); + REGISTER_PROP( PROPERTY_ID_MAXROWS, m_nMaxRows ); + REGISTER_PROP( PROPERTY_ID_QUERYTIMEOUT, m_nQueryTimeOut ); + REGISTER_PROP( PROPERTY_ID_FETCHSIZE, m_nFetchSize ); + REGISTER_PROP( PROPERTY_ID_RESULTSETTYPE, m_nResultSetType ); + REGISTER_PROP( PROPERTY_ID_FETCHDIRECTION, m_nFetchDirection ); + REGISTER_PROP( PROPERTY_ID_ESCAPEPROCESSING, m_bEscapeProcessing ); + REGISTER_PROP( PROPERTY_ID_RESULTSETCONCURRENCY, m_nResultSetConcurrency ); +} + +OCommonStatement::~OCommonStatement() +{ +} + +void OCommonStatement::disposeResultSet() +{ + // free the cursor if alive + Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + m_xResultSet.clear(); +} + +void OCommonStatement::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + disposeResultSet(); + + m_xConnection.clear(); + + OCommonStatement_IBase::disposing(); +} + +Any SAL_CALL OCommonStatement::queryInterface( const Type & rType ) +{ + Any aRet = OCommonStatement_IBase::queryInterface(rType); + if(!aRet.hasValue()) + aRet = ::comphelper::OPropertyContainer::queryInterface(rType); + return aRet; +} + +Sequence< Type > SAL_CALL OCommonStatement::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),OCommonStatement_IBase::getTypes()); +} + + +//void SAL_CALL OCommonStatement::cancel( ) throw(RuntimeException) +//{ +//::osl::MutexGuard aGuard( m_aMutex ); +//checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); +//// cancel the current sql statement +//} + + +void SAL_CALL OCommonStatement::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + } + dispose(); +} + +OUString OCommonStatement::impl_getColumnRefColumnName_throw( const OSQLParseNode& _rColumnRef ) +{ + ENSURE_OR_THROW( SQL_ISRULE( &_rColumnRef, column_ref ), "internal error: only column_refs supported as LHS" ); + + OUString sColumnName; + switch ( _rColumnRef.count() ) + { + case 3: // SQL_TOKEN_NAME '.' column_val + { + const OSQLParseNode* pPunct = _rColumnRef.getChild( 1 ); + const OSQLParseNode* pColVal = _rColumnRef.getChild( 2 ); + if ( SQL_ISPUNCTUATION( pPunct, "." ) + && ( pColVal->count() == 1 ) + ) + { + sColumnName = pColVal->getChild( 0 )->getTokenValue(); + } + } + break; + + case 1: // column + { + sColumnName = _rColumnRef.getChild( 0 )->getTokenValue(); + } + break; + } + + if ( !sColumnName.getLength() ) + m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this ); + + return sColumnName; +} + + +void OCommonStatement::orderByAnalysis( const OSQLParseNode* _pOrderByClause, SortDescriptor& _out_rSort ) +{ + ENSURE_OR_THROW( _pOrderByClause, "NULL node" ); + ENSURE_OR_THROW( SQL_ISRULE( _pOrderByClause, opt_order_by_clause ), "wrong node type" ); + + _out_rSort.clear(); + + const OSQLParseNode* pOrderList = _pOrderByClause->getByRule( OSQLParseNode::ordering_spec_commalist ); + ENSURE_OR_THROW( pOrderList, "unexpected parse tree structure" ); + + for ( size_t i=0; i<pOrderList->count(); ++i ) + { + const OSQLParseNode* pOrderBy = pOrderList->getChild(i); + if ( !pOrderBy || !SQL_ISRULE( pOrderBy, ordering_spec ) ) + continue; + const OSQLParseNode* pColumnRef = pOrderBy->count() == 2 ? pOrderBy->getChild(0) : nullptr; + const OSQLParseNode* pAscDesc = pOrderBy->count() == 2 ? pOrderBy->getChild(1) : nullptr; + ENSURE_OR_THROW( + ( pColumnRef != nullptr ) + && ( pAscDesc != nullptr ) + && SQL_ISRULE( pAscDesc, opt_asc_desc ) + && ( pAscDesc->count() < 2 ), + "ordering_spec structure error" ); + + // column name -> column field + if ( !SQL_ISRULE( pColumnRef, column_ref ) ) + m_xConnection->throwGenericSQLException( STR_SORT_BY_COL_ONLY, *this ); + const OUString sColumnName( impl_getColumnRefColumnName_throw( *pColumnRef ) ); + guint nField = evoab::findEvoabField( sColumnName ); + // ascending/descending? + bool bAscending = true; + if ( ( pAscDesc->count() == 1 ) + && SQL_ISTOKEN( pAscDesc->getChild( 0 ), DESC ) + ) + bAscending = false; + + _out_rSort.push_back( FieldSort( nField, bAscending ) ); + } +} + + +EBookQuery *OCommonStatement::whereAnalysis( const OSQLParseNode* parseTree ) +{ + EBookQuery *pResult = nullptr; + + ENSURE_OR_THROW( parseTree, "invalid parse tree" ); + + // Nested brackets + if( parseTree->count() == 3 && + SQL_ISPUNCTUATION( parseTree->getChild( 0 ), "(" ) && + SQL_ISPUNCTUATION( parseTree->getChild( 2 ), ")" ) ) + { + pResult = whereAnalysis( parseTree->getChild( 1 ) ); + } + + // SQL AND, OR + else if( ( SQL_ISRULE( parseTree, search_condition ) || + SQL_ISRULE( parseTree, boolean_term ) ) && + parseTree->count() == 3 ) + { + ENSURE_OR_THROW( SQL_ISTOKEN( parseTree->getChild( 1 ), OR ) + || SQL_ISTOKEN( parseTree->getChild( 1 ), AND ), + "unexpected search_condition structure" ); + + EBookQuery *pArgs[2]; + pArgs[0] = whereAnalysis( parseTree->getChild( 0 ) ); + pArgs[1] = whereAnalysis( parseTree->getChild( 2 ) ); + + if( SQL_ISTOKEN( parseTree->getChild( 1 ), OR ) ) + pResult = e_book_query_or( 2, pArgs, true ); + else + pResult = e_book_query_and( 2, pArgs, true ); + } + // SQL =, != + else if( SQL_ISRULE( parseTree, comparison_predicate ) ) + { + OSQLParseNode *pPrec = parseTree->getChild( 1 ); + + ENSURE_OR_THROW( parseTree->count() == 3, "unexpected comparison_predicate structure" ); + + OSQLParseNode* pLHS = parseTree->getChild( 0 ); + OSQLParseNode* pRHS = parseTree->getChild( 2 ); + + if ( ( ! SQL_ISRULE( pLHS, column_ref ) // on the LHS, we accept a column or a constant int value + && ( pLHS->getNodeType() != SQLNodeType::IntNum ) + ) + || ( ( pRHS->getNodeType() != SQLNodeType::String ) // on the RHS, certain literals are acceptable + && ( pRHS->getNodeType() != SQLNodeType::IntNum ) + && ( pRHS->getNodeType() != SQLNodeType::ApproxNum ) + && ! SQL_ISTOKEN( pRHS, TRUE ) + && ! SQL_ISTOKEN( pRHS, FALSE ) + ) + || ( ( pLHS->getNodeType() == SQLNodeType::IntNum ) // an int on LHS requires an int on RHS + && ( pRHS->getNodeType() != SQLNodeType::IntNum ) + ) + ) + { + m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this ); + } + + if ( ( pPrec->getNodeType() != SQLNodeType::Equal ) + && ( pPrec->getNodeType() != SQLNodeType::NotEqual ) + ) + { + m_xConnection->throwGenericSQLException( STR_OPERATOR_TOO_COMPLEX, *this ); + } + + // recognize the special "0 = 1" condition + if ( ( pLHS->getNodeType() == SQLNodeType::IntNum ) + && ( pRHS->getNodeType() == SQLNodeType::IntNum ) + && ( pPrec->getNodeType() == SQLNodeType::Equal ) + ) + { + const sal_Int32 nLHS = pLHS->getTokenValue().toInt64(); + const sal_Int32 nRHS = pRHS->getTokenValue().toInt64(); + return ( nLHS == nRHS ) ? createTrue() : nullptr; + } + + OUString aColumnName( impl_getColumnRefColumnName_throw( *pLHS ) ); + + OUString aMatchString; + if ( pRHS->isToken() ) + aMatchString = pRHS->getTokenValue(); + else + aMatchString = pRHS->getChild( 0 )->getTokenValue(); + + pResult = createTest( aColumnName, E_BOOK_QUERY_IS, aMatchString ); + + if ( pResult && ( pPrec->getNodeType() == SQLNodeType::NotEqual ) ) + pResult = e_book_query_not( pResult, true ); + } + // SQL like + else if( SQL_ISRULE( parseTree, like_predicate ) ) + { + ENSURE_OR_THROW( parseTree->count() == 2, "unexpected like_predicate structure" ); + const OSQLParseNode* pPart2 = parseTree->getChild(1); + + if( ! SQL_ISRULE( parseTree->getChild( 0 ), column_ref) ) + m_xConnection->throwGenericSQLException(STR_QUERY_INVALID_LIKE_COLUMN,*this); + + OUString aColumnName( impl_getColumnRefColumnName_throw( *parseTree->getChild( 0 ) ) ); + + OSQLParseNode *pAtom = pPart2->getChild( pPart2->count() - 2 ); // Match String + bool bNotLike = pPart2->getChild(0)->isToken(); + + if( !( pAtom->getNodeType() == SQLNodeType::String || + pAtom->getNodeType() == SQLNodeType::Name || + SQL_ISRULE( pAtom,parameter ) || + ( pAtom->getChild( 0 ) && pAtom->getChild( 0 )->getNodeType() == SQLNodeType::Name ) || + ( pAtom->getChild( 0 ) && pAtom->getChild( 0 )->getNodeType() == SQLNodeType::String ) ) ) + { + SAL_INFO( + "connectivity.evoab2", + "analyseSQL : pAtom->count() = " << pAtom->count()); + m_xConnection->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,*this); + } + + const sal_Unicode WILDCARD = '%'; + + OUString aMatchString = pAtom->getTokenValue(); + + // Determine where '%' character is... + if( aMatchString == OUStringChar(WILDCARD) ) + { + // String containing only a '%' and nothing else matches everything + pResult = createTest( aColumnName, E_BOOK_QUERY_CONTAINS, + "" ); + } + else if( aMatchString.indexOf( WILDCARD ) == -1 ) + { // Simple string , eg. "to match" "contains in evo" + SAL_INFO( "connectivity.evoab2", "Plain contains '" << aMatchString << "'" ); + pResult = createTest( aColumnName, E_BOOK_QUERY_CONTAINS, aMatchString ); + if( pResult && bNotLike ) + pResult = e_book_query_not( pResult, true ); + } + else if( bNotLike ) + { + // We currently can't handle a 'NOT LIKE' when there are '%' + m_xConnection->throwGenericSQLException(STR_QUERY_NOT_LIKE_TOO_COMPLEX,*this); + } + else if( aMatchString.indexOf ( WILDCARD ) == aMatchString.lastIndexOf ( WILDCARD ) ) + { // One occurrence of '%' matches... + if ( aMatchString.startsWith(OUStringChar(WILDCARD)) ) + pResult = createTest( aColumnName, E_BOOK_QUERY_ENDS_WITH, aMatchString.copy( 1 ) ); + else if ( aMatchString.indexOf ( WILDCARD ) == aMatchString.getLength() - 1 ) + pResult = createTest( aColumnName, E_BOOK_QUERY_BEGINS_WITH, aMatchString.copy( 0, aMatchString.getLength() - 1 ) ); + else + m_xConnection->throwGenericSQLException(STR_QUERY_LIKE_WILDCARD,*this); + } + else if( aMatchString.getLength() >= 3 && + aMatchString.startsWith(OUStringChar(WILDCARD)) && + aMatchString.indexOf ( WILDCARD, 1) == aMatchString.getLength() - 1 ) { + // one '%' at the start and another at the end + pResult = createTest( aColumnName, E_BOOK_QUERY_CONTAINS, aMatchString.copy (1, aMatchString.getLength() - 2) ); + } + else + m_xConnection->throwGenericSQLException(STR_QUERY_LIKE_WILDCARD_MANY,*this); + } + + return pResult; +} + +OUString OCommonStatement::getTableName() const +{ + OUString aTableName; + + if( m_pParseTree && m_aSQLIterator.getStatementType() == OSQLStatementType::Select ) + { + Any aCatalog; + OUString aSchema; + const OSQLParseNode *pSelectStmnt = m_aSQLIterator.getParseTree(); + const OSQLParseNode *pAllTableNames = pSelectStmnt->getChild( 3 )->getChild( 0 )->getChild( 1 ); + + if( OSQLParseTreeIterator::isTableNode( pAllTableNames->getChild( 0 ) ) ) + OSQLParseNode::getTableComponents( pAllTableNames->getChild( 0 ), + aCatalog,aSchema, aTableName,nullptr ); + + else if( SQL_ISRULE( pAllTableNames->getChild( 0 ), table_ref ) ) + { + OSQLParseNode *pNodeForTableName = pAllTableNames->getChild( 0 )->getChild( 0 ); + if( OSQLParseTreeIterator::isTableNode( pNodeForTableName ) ) + { + aTableName = OSQLParseNode::getTableRange(pAllTableNames->getChild( 0 )); + if( !aTableName.getLength() ) + OSQLParseNode::getTableComponents( pNodeForTableName, aCatalog, aSchema, aTableName,nullptr); + } + else + OSL_FAIL( "odd table layout" ); + } + else + OSL_FAIL( "unusual table layout" ); + } + return aTableName; +} + +void OCommonStatement::parseSql( const OUString& sql, QueryData& _out_rQueryData ) +{ + SAL_INFO( "connectivity.evoab2", "parsing " << sql ); + + _out_rQueryData.eFilterType = eFilterOther; + + OUString aErr; + m_pParseTree = m_aParser.parseTree( aErr, sql ).release(); + m_aSQLIterator.setParseTree( m_pParseTree ); + m_aSQLIterator.traverseAll(); + + _out_rQueryData.sTable = getTableName(); + + // to be sorted? + const OSQLParseNode* pOrderByClause = m_aSQLIterator.getOrderTree(); + if ( pOrderByClause ) + { + #if OSL_DEBUG_LEVEL > 1 + OUString sTreeDebug; + pOrderByClause->showParseTree( sTreeDebug ); + SAL_INFO( "connectivity.evoab2", "found order-by tree:\n" << sTreeDebug ); + #endif + orderByAnalysis( pOrderByClause, _out_rQueryData.aSortOrder ); + } + + const OSQLParseNode* pWhereClause = m_aSQLIterator.getWhereTree(); + if ( pWhereClause && SQL_ISRULE( pWhereClause, where_clause ) ) + { + #if OSL_DEBUG_LEVEL > 1 + OUString sTreeDebug; + pWhereClause->showParseTree( sTreeDebug ); + SAL_INFO( "connectivity.evoab2", "found where tree:\n" << sTreeDebug ); + #endif + EBookQuery* pQuery = whereAnalysis( pWhereClause->getChild( 1 ) ); + if ( !pQuery ) + { + _out_rQueryData.eFilterType = eFilterAlwaysFalse; + pQuery = createTrue(); + } + _out_rQueryData.setQuery( pQuery ); + } + else + { + _out_rQueryData.eFilterType = eFilterNone; + _out_rQueryData.setQuery( createTrue() ); + } +} + + +Reference< XConnection > SAL_CALL OStatement::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + // just return our connection here + return impl_getConnection(); +} + + +Any SAL_CALL OCommonStatement::getWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + + return makeAny(SQLWarning()); +} + + +void SAL_CALL OCommonStatement::clearWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + +} + +::cppu::IPropertyArrayHelper* OCommonStatement::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +::cppu::IPropertyArrayHelper & OCommonStatement::getInfoHelper() +{ + return *getArrayHelper(); +} + + +void SAL_CALL OCommonStatement::acquire() throw() +{ + OCommonStatement_IBase::acquire(); +} + +void SAL_CALL OCommonStatement::release() throw() +{ + OCommonStatement_IBase::release(); +} + + +QueryData OCommonStatement::impl_getEBookQuery_throw( const OUString& _rSql ) +{ + QueryData aData; + parseSql( _rSql, aData ); + +#if OSL_DEBUG_LEVEL > 1 + char *pSexpr = aData.getQuery() ? e_book_query_to_string( aData.getQuery() ) : g_strdup( "<map failed>" ); + g_message( "Parsed SQL to sexpr '%s'\n", pSexpr ); + g_free( pSexpr ); +#endif + + if ( !aData.getQuery() ) + m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this ); + + // a postcondition of this method is that we properly determined the SELECT columns + aData.xSelectColumns = m_aSQLIterator.getSelectColumns(); + if ( !aData.xSelectColumns.is() ) + m_xConnection->throwGenericSQLException( STR_QUERY_TOO_COMPLEX, *this ); + + return aData; +} + + +Reference< XResultSet > OCommonStatement::impl_executeQuery_throw( const QueryData& _rQueryData ) +{ + // create result set + OEvoabResultSet* pResult = new OEvoabResultSet( this, m_xConnection.get() ); + Reference< XResultSet > xRS = pResult; + pResult->construct( _rQueryData ); + + // done + m_xResultSet = xRS; + return xRS; +} + + +Reference< XResultSet > OCommonStatement::impl_executeQuery_throw( const OUString& _rSql ) +{ + SAL_INFO( "connectivity.evoab2", "OCommonStatement::impl_executeQuery_throw " << _rSql ); + +#if OSL_DEBUG_LEVEL > 1 + g_message( "Parse SQL '%s'\n", + OUStringToOString(_rSql, RTL_TEXTENCODING_UTF8).getStr() ); +#endif + + return impl_executeQuery_throw( impl_getEBookQuery_throw( _rSql ) ); +} + + +Reference< XPropertySetInfo > SAL_CALL OCommonStatement::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ); +} + + +// = OStatement + + +IMPLEMENT_SERVICE_INFO( OStatement, "com.sun.star.comp.sdbcx.evoab.OStatement", "com.sun.star.sdbc.Statement" ); + + +IMPLEMENT_FORWARD_XINTERFACE2( OStatement, OCommonStatement, OStatement_IBase ) + + +IMPLEMENT_FORWARD_XTYPEPROVIDER2( OStatement, OCommonStatement, OStatement_IBase ) + + +sal_Bool SAL_CALL OStatement::execute( const OUString& _sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + Reference< XResultSet > xRS = impl_executeQuery_throw( _sql ); + return xRS.is(); +} + + +Reference< XResultSet > SAL_CALL OStatement::executeQuery( const OUString& _sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + + return impl_executeQuery_throw( _sql ); +} + + +sal_Int32 SAL_CALL OStatement::executeUpdate( const OUString& /*sql*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBase::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "XStatement::executeUpdate", *this ); + return 0; +} + +} // namespace ::connectivity::evoab + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NStatement.hxx b/connectivity/source/drivers/evoab2/NStatement.hxx new file mode 100644 index 000000000..14c12700c --- /dev/null +++ b/connectivity/source/drivers/evoab2/NStatement.hxx @@ -0,0 +1,278 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NSTATEMENT_HXX + +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <comphelper/proparrhlp.hxx> +#include <cppuhelper/implbase2.hxx> +#include <cppuhelper/basemutex.hxx> +#include <comphelper/uno3.hxx> +#include <connectivity/CommonTools.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <connectivity/sqliterator.hxx> +#include <connectivity/sqlparse.hxx> +#include <connectivity/FValue.hxx> +#include <com/sun/star/util/XCancellable.hpp> +#include <cppuhelper/compbase.hxx> +#include <comphelper/propertycontainer.hxx> + +#include "EApi.h" +#include "NConnection.hxx" + +#include <list> + +namespace connectivity +{ + namespace evoab + { + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier + , css::sdbc::XCloseable + > OCommonStatement_IBase; + + struct FieldSort + { + sal_Int32 nField; + bool bAscending; + + FieldSort( const sal_Int32 _nField, const bool _bAscending ) : nField( _nField ), bAscending( _bAscending ) { } + }; + typedef std::vector< FieldSort > SortDescriptor; + + enum QueryFilterType + { + eFilterAlwaysFalse, + eFilterNone, + eFilterOther + }; + + class EBookQueryWrapper + { + private: + EBookQuery* mpQuery; + public: + EBookQueryWrapper() + : mpQuery(nullptr) + { + } + EBookQueryWrapper(const EBookQueryWrapper& rhs) + : mpQuery(rhs.mpQuery) + { + if (mpQuery) + e_book_query_ref(mpQuery); + } + EBookQueryWrapper(EBookQueryWrapper&& rhs) noexcept + : mpQuery(rhs.mpQuery) + { + rhs.mpQuery = nullptr; + } + void reset(EBookQuery* pQuery) + { + if (mpQuery) + e_book_query_unref(mpQuery); + mpQuery = pQuery; + if (mpQuery) + e_book_query_ref(mpQuery); + } + EBookQueryWrapper& operator=(const EBookQueryWrapper& rhs) + { + if (this != &rhs) + reset(rhs.mpQuery); + return *this; + } + EBookQueryWrapper& operator=(EBookQueryWrapper&& rhs) + { + if (mpQuery) + e_book_query_unref(mpQuery); + mpQuery = rhs.mpQuery; + rhs.mpQuery = nullptr; + return *this; + } + ~EBookQueryWrapper() + { + if (mpQuery) + e_book_query_unref(mpQuery); + } + EBookQuery* getQuery() const + { + return mpQuery; + } + }; + + struct QueryData + { + private: + EBookQueryWrapper aQuery; + + public: + OUString sTable; + QueryFilterType eFilterType; + rtl::Reference<connectivity::OSQLColumns> xSelectColumns; + SortDescriptor aSortOrder; + + QueryData() + : sTable() + , eFilterType( eFilterOther ) + , xSelectColumns() + , aSortOrder() + { + } + + EBookQuery* getQuery() const { return aQuery.getQuery(); } + void setQuery(EBookQuery* pQuery) { aQuery.reset(pQuery); } + }; + + //************ Class: OCommonStatement + // is a base class for the normal statement and for the prepared statement + + class OCommonStatement :public cppu::BaseMutex + ,public OCommonStatement_IBase + ,public ::comphelper::OPropertyContainer + ,public ::comphelper::OPropertyArrayUsageHelper< OCommonStatement > + { + private: + css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created + rtl::Reference<OEvoabConnection> m_xConnection; + connectivity::OSQLParser m_aParser; + connectivity::OSQLParseTreeIterator m_aSQLIterator; + connectivity::OSQLParseNode *m_pParseTree; + + // <properties> + OUString m_aCursorName; + sal_Int32 m_nMaxFieldSize; + sal_Int32 m_nMaxRows; + sal_Int32 m_nQueryTimeOut; + sal_Int32 m_nFetchSize; + sal_Int32 m_nResultSetType; + sal_Int32 m_nFetchDirection; + sal_Int32 m_nResultSetConcurrency; + bool m_bEscapeProcessing; + // </properties> + + protected: + + void disposeResultSet(); + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual ~OCommonStatement() override; + + protected: + void parseSql( const OUString& sql, QueryData& _out_rQueryData ); + EBookQuery *whereAnalysis( const OSQLParseNode* parseTree ); + void orderByAnalysis( const OSQLParseNode* _pOrderByClause, SortDescriptor& _out_rSort ); + OUString getTableName() const; + + public: + + // other methods + OEvoabConnection* getOwnConnection() const { return m_xConnection.get(); } + + using OCommonStatement_IBase::operator css::uno::Reference< css::uno::XInterface >; + + protected: + explicit OCommonStatement( OEvoabConnection* _pConnection ); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual void SAL_CALL release() throw() override; + virtual void SAL_CALL acquire() throw() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + + // XCloseable + virtual void SAL_CALL close( ) override; + + protected: + /** will return the EBookQuery representing the statement WHERE condition, or throw + + Also, all statement dependent members (such as the parser/iterator) will be inited afterwards. + */ + QueryData + impl_getEBookQuery_throw( const OUString& _rSql ); + + css::uno::Reference< css::sdbc::XResultSet > + impl_executeQuery_throw( const OUString& _rSql ); + + css::uno::Reference< css::sdbc::XResultSet > + impl_executeQuery_throw( const QueryData& _rData ); + + css::uno::Reference< css::sdbc::XConnection > + impl_getConnection() { return css::uno::Reference< css::sdbc::XConnection >( m_xConnection.get() ); } + + OUString + impl_getColumnRefColumnName_throw( const ::connectivity::OSQLParseNode& _rColumnRef ); + }; + + typedef ::cppu::ImplHelper2 < css::lang::XServiceInfo + , css::sdbc::XStatement + > OStatement_IBase; + class OStatement :public OCommonStatement + ,public OStatement_IBase + { + protected: + virtual ~OStatement() override {} + + public: + explicit OStatement( OEvoabConnection* _pConnection) + :OCommonStatement( _pConnection) + { + } + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + // XTypeProvider + DECLARE_XTYPEPROVIDER() + + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ; + virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ; + virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NTable.cxx b/connectivity/source/drivers/evoab2/NTable.cxx new file mode 100644 index 000000000..b5c652a8f --- /dev/null +++ b/connectivity/source/drivers/evoab2/NTable.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "NTable.hxx" +#include "NColumns.hxx" + +#include <com/sun/star/sdbc/XRow.hpp> + +using namespace connectivity; +using namespace ::comphelper; +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 connectivity::evoab; + +OEvoabTable::OEvoabTable( sdbcx::OCollection* _pTables, + OEvoabConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName + ) : OEvoabTable_TYPEDEF(_pTables,true, + Name, + Type, + Description, + SchemaName, + CatalogName), + m_pConnection(_pConnection) +{ + construct(); +} + +void OEvoabTable::refreshColumns() +{ + ::std::vector< OUString> aVector; + + if (!isNew()) + { + Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns( + Any(), m_SchemaName, m_Name, "%"); + + if (xResult.is()) + { + Reference< XRow > xRow(xResult, UNO_QUERY); + while (xResult->next()) + aVector.push_back(xRow->getString(4)); + } + } + if (m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns = new OEvoabColumns(this,m_aMutex,aVector); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NTable.hxx b/connectivity/source/drivers/evoab2/NTable.hxx new file mode 100644 index 000000000..eb1159847 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NTable.hxx @@ -0,0 +1,58 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NTABLE_HXX + +#include "NConnection.hxx" +#include <connectivity/sdbcx/VTable.hxx> + +namespace connectivity +{ + namespace evoab + { + typedef connectivity::sdbcx::OTable OEvoabTable_TYPEDEF; + + class OEvoabTable : public OEvoabTable_TYPEDEF + { + OEvoabConnection* m_pConnection; + + public: + OEvoabTable( sdbcx::OCollection* _pTables, + OEvoabConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description, + const OUString& SchemaName, + const OUString& CatalogName + ); + + OEvoabConnection* getConnection() { return m_pConnection;} + + virtual void refreshColumns() override; + + OUString const & getTableName() const { return m_Name; } + OUString const & getSchema() const { return m_SchemaName; } + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NTables.cxx b/connectivity/source/drivers/evoab2/NTables.cxx new file mode 100644 index 000000000..b7a844fac --- /dev/null +++ b/connectivity/source/drivers/evoab2/NTables.cxx @@ -0,0 +1,80 @@ +/* -*- 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 "NTables.hxx" +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include "NCatalog.hxx" +#include <comphelper/types.hxx> +#include "NTable.hxx" +using namespace ::comphelper; + +using namespace ::cppu; +using namespace connectivity::evoab; +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 dbtools; + +ObjectType OEvoabTables::createObject(const OUString& aName) +{ + Sequence< OUString > aTypes { "TABLE" }; + + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(),"%",aName,aTypes); + + ObjectType xRet; + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + if(xResult->next()) // there can be only one table with this name + { + OEvoabTable* pRet = new OEvoabTable( + this, + static_cast<OEvoabCatalog&>(m_rParent).getConnection(), + aName, + xRow->getString(4), + xRow->getString(5), + "", + ""); + xRet = pRet; + } + } + + ::comphelper::disposeComponent(xResult); + + return xRet; +} + +void OEvoabTables::impl_refresh( ) +{ + static_cast<OEvoabCatalog&>(m_rParent).refreshTables(); +} + +void OEvoabTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/NTables.hxx b/connectivity/source/drivers/evoab2/NTables.hxx new file mode 100644 index 000000000..99542ba53 --- /dev/null +++ b/connectivity/source/drivers/evoab2/NTables.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NTABLES_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +namespace connectivity +{ + namespace evoab + { + class OEvoabTables : public sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + public: + OEvoabTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData, + ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : + sdbcx::OCollection(_rParent,true,_rMutex,_rVector), + m_xMetaData(_rMetaData) + {} + virtual void disposing() override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_EVOAB2_NTABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/evoab2/evoab.component b/connectivity/source/drivers/evoab2/evoab.component new file mode 100644 index 000000000..6bd8cb5e3 --- /dev/null +++ b/connectivity/source/drivers/evoab2/evoab.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="evoab2" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.evoab.OEvoabDriver"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/file/FCatalog.cxx b/connectivity/source/drivers/file/FCatalog.cxx new file mode 100644 index 000000000..eedda26ef --- /dev/null +++ b/connectivity/source/drivers/file/FCatalog.cxx @@ -0,0 +1,103 @@ +/* -*- 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 <file/FCatalog.hxx> +#include <file/FConnection.hxx> +#include <file/FTables.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> + +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 connectivity::file; + +OFileCatalog::OFileCatalog(OConnection* _pCon) : connectivity::sdbcx::OCatalog(_pCon) + ,m_pConnection(_pCon) +{ +} + +void SAL_CALL OFileCatalog::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + typedef connectivity::sdbcx::OCatalog OFileCatalog_BASE; + m_xMetaData.clear(); + OFileCatalog_BASE::disposing(); +} + +OUString OFileCatalog::buildName(const Reference< XRow >& _xRow) +{ + return _xRow->getString(3); +} + +void OFileCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + Sequence< OUString > aTypes; + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), + "%", "%", aTypes); + fillNames(xResult,aVector); + + if(m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset( new OTables(m_xMetaData,*this,m_aMutex,aVector) ); +} + + +Any SAL_CALL OFileCatalog::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType<XGroupsSupplier>::get()|| + rType == cppu::UnoType<XUsersSupplier>::get()|| + rType == cppu::UnoType<XViewsSupplier>::get()) + return Any(); + + + typedef sdbcx::OCatalog OFileCatalog_BASE; + return OFileCatalog_BASE::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OFileCatalog::getTypes( ) +{ + typedef sdbcx::OCatalog OFileCatalog_BASE; + + Sequence< Type > aTypes = OFileCatalog_BASE::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!(*pBegin == cppu::UnoType<XGroupsSupplier>::get()|| + *pBegin == cppu::UnoType<XUsersSupplier>::get()|| + *pBegin == cppu::UnoType<XViewsSupplier>::get())) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FColumns.cxx b/connectivity/source/drivers/file/FColumns.cxx new file mode 100644 index 000000000..e703112f7 --- /dev/null +++ b/connectivity/source/drivers/file/FColumns.cxx @@ -0,0 +1,81 @@ +/* -*- 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 <file/FColumns.hxx> +#include <connectivity/sdbcx/VColumn.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <file/FTable.hxx> + +using namespace connectivity::file; +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; + +sdbcx::ObjectType OColumns::createObject(const OUString& _rName) +{ + const OUString sCatalogName; + const OUString sSchemaName(m_pTable->getSchema()); + const OUString sTableName(m_pTable->getName()); + Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns(Any(), + sSchemaName, sTableName, _rName); + + sdbcx::ObjectType xRet; + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while(xResult->next()) + { + if(xRow->getString(4) == _rName) + { + sdbcx::OColumn* pRet = new sdbcx::OColumn(_rName, + xRow->getString(6), + xRow->getString(13), + xRow->getString(12), + xRow->getInt(11), + xRow->getInt(7), + xRow->getInt(9), + xRow->getInt(5), + false, + false, + false, + m_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(), + sCatalogName, + sSchemaName, + sTableName); + xRet = pRet; + break; + } + } + } + + return xRet; +} + +void OColumns::impl_refresh() +{ + m_pTable->refreshColumns(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FConnection.cxx b/connectivity/source/drivers/file/FConnection.cxx new file mode 100644 index 000000000..5c56ce4d5 --- /dev/null +++ b/connectivity/source/drivers/file/FConnection.cxx @@ -0,0 +1,435 @@ +/* -*- 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 <comphelper/processfactory.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <file/FConnection.hxx> +#include <file/FDatabaseMetaData.hxx> +#include <file/FDriver.hxx> +#include <file/FStatement.hxx> +#include <file/FPreparedStatement.hxx> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/ucb/ContentCreationException.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XContentIdentifier.hpp> +#include <tools/urlobj.hxx> +#include <file/FCatalog.hxx> +#include <unotools/pathoptions.hxx> +#include <ucbhelper/content.hxx> +#include <connectivity/dbcharset.hxx> +#include <connectivity/dbexception.hxx> +#include <o3tl/any.hxx> +#include <osl/thread.h> +#include <strings.hrc> + +using namespace connectivity::file; +using namespace dbtools; + +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::ucb; +using namespace ::ucbhelper; +typedef connectivity::OMetaConnection OConnection_BASE; + +OConnection::OConnection(OFileDriver* _pDriver) + : m_pDriver(_pDriver) + , m_bAutoCommit(false) + , m_bReadOnly(false) + , m_bShowDeleted(false) + , m_bCaseSensitiveExtension( true ) + , m_bCheckSQL92(false) + , m_bDefaultTextEncoding(false) +{ + m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW; +} + +OConnection::~OConnection() +{ + if(!isClosed( )) + close(); +} + +bool OConnection::matchesExtension( const OUString& _rExt ) const +{ + if ( isCaseSensitiveExtension() ) + return ( getExtension() == _rExt ); + + OUString sMyExtension( getExtension().toAsciiLowerCase() ); + OUString sExt( _rExt.toAsciiLowerCase() ); + + return sMyExtension == sExt; +} + + +void OConnection::construct(const OUString& url,const Sequence< PropertyValue >& info) +{ + osl_atomic_increment( &m_refCount ); + + OUString aExt; + const PropertyValue *pIter = info.getConstArray(); + const PropertyValue *pEnd = pIter + info.getLength(); + for(;pIter != pEnd;++pIter) + { + if( pIter->Name == "Extension" ) + OSL_VERIFY( pIter->Value >>= aExt ); + else if( pIter->Name == "CharSet" ) + { + if (auto const numeric = o3tl::tryAccess<sal_uInt16>(pIter->Value)) + { + m_nTextEncoding = *numeric; + } + else + { + OUString sIanaName; + OSL_VERIFY( pIter->Value >>= sIanaName ); + + ::dbtools::OCharsetMap aLookupIanaName; + ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName); + if (aLookup != aLookupIanaName.end()) + m_nTextEncoding = (*aLookup).getEncoding(); + else + m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW; + } + } + else if( pIter->Name == "ShowDeleted" ) + { + OSL_VERIFY( pIter->Value >>= m_bShowDeleted ); + } + else if( pIter->Name == "EnableSQL92Check" ) + { + pIter->Value >>= m_bCheckSQL92; + } + } // for(;pIter != pEnd;++pIter) + + { + sal_Int32 nLen = url.indexOf(':'); + nLen = url.indexOf(':',nLen+1); + OUString aDSN(url.copy(nLen+1)); + + OUString aFileName = aDSN; + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + { + SvtPathOptions aPathOptions; + aFileName = aPathOptions.SubstituteVariable(aFileName); + } + + aURL.SetSmartURL(aFileName); + + setURL(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + } + + if ( m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW ) + { + //m_nTextEncoding = osl_getTextEncodingFromLocale(NULL); + m_nTextEncoding = osl_getThreadTextEncoding(); + m_bDefaultTextEncoding = true; + } + + if ( !aExt.isEmpty() ) + m_aFilenameExtension = aExt; + + try + { + ::ucbhelper::Content aFile; + try + { + aFile = ::ucbhelper::Content(getURL(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext()); + } + catch(ContentCreationException& e) + { + throwUrlNotValid(getURL(),e.Message); + } + + // set fields to fetch + Sequence< OUString > aProps { "Title" }; + + try + { + if (aFile.isFolder()) + { + m_xDir = aFile.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ); + m_xContent = aFile.get(); + } + else if (aFile.isDocument()) + { + Reference<XContent> xParent(Reference<XChild>(aFile.get(),UNO_QUERY_THROW)->getParent(),UNO_QUERY_THROW); + Reference<XContentIdentifier> xIdent = xParent->getIdentifier(); + m_xContent = xParent; + + ::ucbhelper::Content aParent(xIdent->getContentIdentifier(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext()); + m_xDir = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ); + } + else + { + OSL_FAIL("OConnection::construct: ::ucbhelper::Content is neither a folder nor a document! How's that?!"); + throw SQLException(); + } + } + catch(Exception& e) // an exception is thrown when no file exists + { + throwUrlNotValid(getURL(),e.Message); + } + if(!m_xDir.is() || !m_xContent.is()) + throwUrlNotValid(getURL(),OUString()); + + if (m_aFilenameExtension.indexOf('*') >= 0 || m_aFilenameExtension.indexOf('?') >= 0) + throw SQLException(); + } + catch(const Exception&) + { + osl_atomic_decrement( &m_refCount ); + throw; + } + + osl_atomic_decrement( &m_refCount ); +} +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.file.Connection", "com.sun.star.sdbc.Connection") + + +Reference< XStatement > SAL_CALL OConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + Reference< XStatement > xReturn = new OStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OPreparedStatement* pStmt = new OPreparedStatement(this); + Reference< XPreparedStatement > xHoldAlive = pStmt; + pStmt->construct(sql); + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return pStmt; +} + +Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ ) +{ + throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this ); + return nullptr; +} + +OUString SAL_CALL OConnection::nativeSQL( const OUString& sql ) +{ + return sql; +} + +void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + m_bAutoCommit = autoCommit; +} + +sal_Bool SAL_CALL OConnection::getAutoCommit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + return m_bAutoCommit; +} + +void SAL_CALL OConnection::commit( ) +{ +} + +void SAL_CALL OConnection::rollback( ) +{ +} + +sal_Bool SAL_CALL OConnection::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return OConnection_BASE::rBHelper.bDisposed; +} + +Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new ODatabaseMetaData(this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + m_bReadOnly = readOnly; +} + +sal_Bool SAL_CALL OConnection::isReadOnly( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + return m_bReadOnly; +} + +void SAL_CALL OConnection::setCatalog( const OUString& /*catalog*/ ) +{ + throwFeatureNotImplementedSQLException( "XConnection::setCatalog", *this ); +} + +OUString SAL_CALL OConnection::getCatalog( ) +{ + return OUString(); +} + +void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 /*level*/ ) +{ + throwFeatureNotImplementedSQLException( "XConnection::setTransactionIsolation", *this ); +} + +sal_Int32 SAL_CALL OConnection::getTransactionIsolation( ) +{ + return 0; +} + +Reference< XNameAccess > SAL_CALL OConnection::getTypeMap( ) +{ + return nullptr; +} + +void SAL_CALL OConnection::setTypeMap( const Reference< XNameAccess >& /*typeMap*/ ) +{ +} + +// XCloseable +void SAL_CALL OConnection::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + } + dispose(); +} + +// XWarningsSupplier +Any SAL_CALL OConnection::getWarnings( ) +{ + return Any(); +} + +void SAL_CALL OConnection::clearWarnings( ) +{ +} + +void OConnection::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + OConnection_BASE::disposing(); + + m_xDir.clear(); + m_xContent.clear(); + m_xCatalog = WeakReference< XTablesSupplier>(); +} + +Reference< XTablesSupplier > OConnection::createCatalog() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XTablesSupplier > xTab = m_xCatalog; + if(!xTab.is()) + { + xTab = new OFileCatalog(this); + m_xCatalog = xTab; + } + return xTab; +} + +Reference< XDynamicResultSet > OConnection::getDir() const +{ + Reference<XDynamicResultSet> xContent; + Sequence< OUString > aProps { "Title" }; + try + { + Reference<XContentIdentifier> xIdent = getContent()->getIdentifier(); + ::ucbhelper::Content aParent(xIdent->getContentIdentifier(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext()); + xContent = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ); + } + catch(Exception&) + { + } + return xContent; +} + +sal_Int64 SAL_CALL OConnection::getSomething( const Sequence< sal_Int8 >& rId ) +{ + return (isUnoTunnelId<OConnection>(rId)) + ? reinterpret_cast< sal_Int64 >( this ) + : sal_Int64(0); +} + +Sequence< sal_Int8 > OConnection::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +void OConnection::throwUrlNotValid(const OUString & _rsUrl,const OUString & _rsMessage) +{ + SQLException aError; + aError.Message = getResources().getResourceStringWithSubstitution( + STR_NO_VALID_FILE_URL, + "$URL$", _rsUrl + ); + + aError.SQLState = "S1000"; + aError.ErrorCode = 0; + aError.Context = static_cast< XConnection* >(this); + if (!_rsMessage.isEmpty()) + aError.NextException <<= SQLException(_rsMessage, aError.Context, OUString(), 0, Any()); + + throw aError; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FDatabaseMetaData.cxx b/connectivity/source/drivers/file/FDatabaseMetaData.cxx new file mode 100644 index 000000000..3d01216a3 --- /dev/null +++ b/connectivity/source/drivers/file/FDatabaseMetaData.cxx @@ -0,0 +1,1055 @@ +/* -*- 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 <file/FDatabaseMetaData.hxx> +#include <FDatabaseMetaDataResultSet.hxx> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/ucb/UniversalContentBroker.hpp> +#include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp> +#include <tools/urlobj.hxx> +#include <sal/log.hxx> +#include <file/FDriver.hxx> +#include <file/FTable.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/servicehelper.hxx> +#include <tools/diagnose_ex.h> +#include <ucbhelper/content.hxx> + +using namespace com::sun::star::ucb; +using namespace connectivity::file; +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::sdbcx; +using namespace com::sun::star::container; + +ODatabaseMetaData::ODatabaseMetaData(OConnection* _pCon) : ::connectivity::ODatabaseMetaDataBase(_pCon,_pCon->getConnectionInfo()) + ,m_pConnection(_pCon) +{ +} + +ODatabaseMetaData::~ODatabaseMetaData() +{ +} + +Reference< XResultSet > ODatabaseMetaData::impl_getTypeInfo_throw( ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTypeInfo ); +} + +OUString ODatabaseMetaData::impl_getCatalogSeparator_throw( ) +{ + return OUString(); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*tableNamePattern*/, + const OUString& /*columnNamePattern*/ ) +{ + SAL_WARN("connectivity.drivers", "ODatabaseMetaData::getColumns() should be overridden!"); + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumns ); +} + + +namespace +{ + sal_Int16 isCaseSensitiveParentFolder( const OUString& _rFolderOrDoc, const OUString& _rDocName ) + { + sal_Int16 nIsCS = 1; + try + { + // first get the real content for the URL + INetURLObject aContentURL( _rFolderOrDoc ); + ::ucbhelper::Content aContent1; + { + ::ucbhelper::Content aFolderOrDoc( _rFolderOrDoc, Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + if ( aFolderOrDoc.isDocument() ) + aContent1 = aFolderOrDoc; + else + { + aContentURL = INetURLObject( _rFolderOrDoc, INetURLObject::EncodeMechanism::WasEncoded ); + aContentURL.Append( _rDocName ); + aContent1 = ::ucbhelper::Content( aContentURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + } + } + + // get two extensions which differ by case only + OUString sExtension1(aContentURL.getExtension()); + OUString sExtension2(sExtension1.toAsciiLowerCase()); + if (sExtension2 == sExtension1) + { + // the extension was already in lower case + sExtension2 = sExtension2.toAsciiUpperCase(); + } + + // the complete URL for the second extension + INetURLObject aURL2( aContentURL ); + if (!sExtension2.isEmpty()) + aURL2.SetExtension( sExtension2 ); + if ( aURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE) == aContentURL.GetMainURL(INetURLObject::DecodeMechanism::NONE) ) + return -1; + + // the second context + bool bCanAccess = false; + ::ucbhelper::Content aContent2; + try + { + aContent2 = ::ucbhelper::Content( aURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() ); + bCanAccess = aContent2.isDocument(); + } + catch( const Exception& ) + { + } + + if ( bCanAccess ) + { + // here we have two contents whose URLs differ by case only. + // Now let's check if both really refer to the same object... + Reference< XContent > xContent1 = aContent1.get(); + Reference< XContent > xContent2 = aContent2.get(); + OSL_ENSURE( xContent1.is() && xContent2.is(), "isCaseSensitiveParentFolder: invalid content interfaces!" ); + if ( xContent1.is() && xContent2.is() ) + { + Reference< XContentIdentifier > xID1 = xContent1->getIdentifier(); + Reference< XContentIdentifier > xID2 = xContent2->getIdentifier(); + OSL_ENSURE( xID1.is() && xID2.is(), "isCaseSensitiveParentFolder: invalid ID interfaces!" ); + if ( xID1.is() && xID2.is() + && ( UniversalContentBroker::create( + comphelper::getProcessComponentContext() )-> + compareContentIds( xID1, xID2 ) == 0 ) ) + { + // finally, we know that the folder is not case-sensitive... + nIsCS = 0; + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.drivers", "isCaseSensitiveParentFolder" ); + } + + return nIsCS; + } +} + + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, + const OUString& tableNamePattern, const Sequence< OUString >& types ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTables ); + Reference< XResultSet > xRef = pResult; + + // check if any type is given + // when no types are given then we have to return all tables e.g. TABLE + + static const char aTable[] = "TABLE"; + + bool bTableFound = true; + sal_Int32 nLength = types.getLength(); + if(nLength) + { + bTableFound = false; + + const OUString* pBegin = types.getConstArray(); + const OUString* pEnd = pBegin + nLength; + for(;pBegin != pEnd;++pBegin) + { + if(*pBegin == aTable) + { + bTableFound = true; + break; + } + } + } + if(!bTableFound) + return xRef; + + Reference<XDynamicResultSet> xContent = m_pConnection->getDir(); + Reference < XSortedDynamicResultSetFactory > xSRSFac = + SortedDynamicResultSetFactory::create( m_pConnection->getDriver()->getComponentContext() ); + + Sequence< NumberedSortingInfo > aSortInfo( 1 ); + NumberedSortingInfo* pInfo = aSortInfo.getArray(); + pInfo[ 0 ].ColumnIndex = 1; + pInfo[ 0 ].Ascending = true; + + Reference < XAnyCompareFactory > xFactory; + Reference< XDynamicResultSet > xDynamicResultSet = xSRSFac->createSortedDynamicResultSet( xContent, aSortInfo, xFactory ); + Reference<XResultSet> xResultSet = xDynamicResultSet->getStaticResultSet(); + + Reference<XRow> xRow(xResultSet,UNO_QUERY); + + OUString aFilenameExtension = m_pConnection->getExtension(); + OUString sThisContentExtension; + ODatabaseMetaDataResultSet::ORows aRows; + // scan the directory for tables + OUString aName; + INetURLObject aURL; + xResultSet->beforeFirst(); + + bool bKnowCaseSensivity = false; + bool bCaseSensitiveDir = true; + bool bCheckEnabled = m_pConnection->isCheckEnabled(); + + while(xResultSet->next()) + { + aName = xRow->getString(1); + aURL.SetSmartProtocol(INetProtocol::File); + OUString sUrl = m_pConnection->getURL() + "/" + aName; + aURL.SetSmartURL( sUrl ); + sThisContentExtension = aURL.getExtension(); + + ODatabaseMetaDataResultSet::ORow aRow { nullptr, nullptr, nullptr }; + aRow.reserve(6); + bool bNewRow = false; + + if ( !bKnowCaseSensivity ) + { + bKnowCaseSensivity = true; + sal_Int16 nCase = isCaseSensitiveParentFolder( m_pConnection->getURL(), aURL.getName() ); + switch( nCase ) + { + case 1: + bCaseSensitiveDir = true; + break; + case -1: + bKnowCaseSensivity = false; + [[fallthrough]]; + case 0: + bCaseSensitiveDir = false; + } + if ( bKnowCaseSensivity ) + { + m_pConnection->setCaseSensitiveExtension( bCaseSensitiveDir, OConnection::GrantAccess() ); + if ( !bCaseSensitiveDir ) + { + aFilenameExtension = aFilenameExtension.toAsciiLowerCase(); + } + } + } + + if (!aFilenameExtension.isEmpty()) + { + if ( !bCaseSensitiveDir ) + { + sThisContentExtension = sThisContentExtension.toAsciiLowerCase(); + } + + if ( sThisContentExtension == aFilenameExtension ) + { + aName = aName.copy(0, (aName.getLength()-(aFilenameExtension.getLength()+1))); + sal_Unicode nChar = aName.toChar(); + if ( match(tableNamePattern,aName,'\0') && ( !bCheckEnabled || (nChar < '0' || nChar > '9')) ) + { + aRow.push_back(new ORowSetValueDecorator(aName)); + bNewRow = true; + } + } + } + else // no extension, filter myself + { + for (;;) + { + if (aURL.getExtension().isEmpty()) + { + sal_Unicode nChar = aURL.getBase()[0]; + if( match(tableNamePattern,aURL.getBase(),'\0') && ( !bCheckEnabled || nChar < '0' || nChar > '9' ) ) + { + aRow.push_back(new ORowSetValueDecorator(aURL.getBase())); + bNewRow = true; + } + break; + } + if ( !xResultSet->next() ) + { + break; + } + aName = xRow->getString(1); + aURL.SetSmartURL(aName); + } + } + if(bNewRow) + { + aRow.push_back(new ORowSetValueDecorator(OUString(aTable))); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + + aRows.push_back(aRow); + } + } + + pResult->setRows(aRows); + + return xRef; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength( ) +{ + return SAL_MAX_INT32; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable( ) +{ + return 0; +} + +sal_Int32 ODatabaseMetaData::impl_getMaxStatements_throw( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength( ) +{ + return 0; +} + +sal_Int32 ODatabaseMetaData::impl_getMaxTablesInSelect_throw( ) +{ + return 1; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges ); + Reference< XResultSet > xRef = pResult; + ODatabaseMetaDataResultSet::ORows aRows; + + + Reference< XTablesSupplier > xTabSup = m_pConnection->createCatalog(); + if( xTabSup.is()) + { + Reference< XNameAccess> xNames = xTabSup->getTables(); + Sequence< OUString > aNames = xNames->getElementNames(); + const OUString* pBegin = aNames.getConstArray(); + const OUString* pEnd = pBegin + aNames.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(match(tableNamePattern,*pBegin,'\0')) + { + ODatabaseMetaDataResultSet::ORow aRow(8); + + aRow[2] = new ORowSetValueDecorator(*pBegin); + aRow[6] = ODatabaseMetaDataResultSet::getSelectValue(); + aRow[7] = new ORowSetValueDecorator(OUString("NO")); + aRows.push_back(aRow); + + Reference< XPropertySet> xTable( + xNames->getByName(*pBegin), css::uno::UNO_QUERY); + if(xTable.is()) + { + auto pTable = comphelper::getUnoTunnelImplementation<OFileTable>(xTable); + if(pTable && !pTable->isReadOnly()) + { + aRow[6] = ODatabaseMetaDataResultSet::getInsertValue(); + aRows.push_back(aRow); + if(!m_pConnection->showDeleted()) + { + 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); + } + } + } + } + } + + pResult->setRows(aRows); + return xRef; +} + +sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( ) +{ + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( ) +{ + return 0; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( ) +{ + return false; +} + +OUString SAL_CALL ODatabaseMetaData::getCatalogTerm( ) +{ + return OUString(); +} + +OUString ODatabaseMetaData::impl_getIdentifierQuoteString_throw( ) +{ + return "\""; +} + +OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + return true; +} + +bool ODatabaseMetaData::impl_isCatalogAtStart_throw( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 /*level*/ ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins( ) +{ + return false; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTableTypes ); + Reference< XResultSet > xRef = pResult; + static ODatabaseMetaDataResultSet::ORows aRows; + if(aRows.empty()) + { + ODatabaseMetaDataResultSet::ORow aRow; + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(OUString("TABLE"))); + aRows.push_back(aRow); + } + pResult->setRows(aRows); + return xRef; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength( ) +{ + return 0; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert( sal_Int32 /*fromType*/, sal_Int32 /*toType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + return true; +} + +bool ODatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + return false; +} + +OUString SAL_CALL ODatabaseMetaData::getURL( ) +{ + return "sdbc:file:"; +} + +OUString SAL_CALL ODatabaseMetaData::getUserName( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getDriverName( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getDriverVersion( ) +{ + return OUString::number(1); +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( ) +{ + return OUString::number(0); +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getSchemaTerm( ) +{ + return OUString(); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( ) +{ + return 0; +} + +OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getStringFunctions( ) +{ + return "UCASE,LCASE,ASCII,LENGTH,OCTET_LENGTH,CHAR_LENGTH,CHARACTER_LENGTH,CHAR,CONCAT,LOCATE,SUBSTRING,LTRIM,RTRIM,SPACE,REPLACE,REPEAT,INSERT,LEFT,RIGHT"; +} + +OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( ) +{ + return "DAYOFWEEK,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,CURDATE,CURTIME,NOW"; +} + +OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( ) +{ + return "ABS,SIGN,MOD,FLOOR,CEILING,ROUND,EXP,LN,LOG,LOG10,POWER,SQRT,PI,COS,SIN,TAN,ACOS,ASIN,ATAN,ATAN2,DEGREES,RADIANS"; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( ) +{ + return 0; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType( sal_Int32 setType ) +{ + switch(setType) + { + case ResultSetType::FORWARD_ONLY: + return true; + case ResultSetType::SCROLL_INSENSITIVE: + case ResultSetType::SCROLL_SENSITIVE: + break; + } + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 /*concurrency*/ ) +{ + switch(setType) + { + case ResultSetType::FORWARD_ONLY: + return true; + case ResultSetType::SCROLL_INSENSITIVE: + case ResultSetType::SCROLL_SENSITIVE: + break; + } + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates( ) +{ + return false; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ ) +{ + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FDateFunctions.cxx b/connectivity/source/drivers/file/FDateFunctions.cxx new file mode 100644 index 000000000..5f9d14418 --- /dev/null +++ b/connectivity/source/drivers/file/FDateFunctions.cxx @@ -0,0 +1,280 @@ +/* -*- 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 <file/FDateFunctions.hxx> +#include <tools/date.hxx> +#include <tools/time.hxx> +#include <tools/datetime.hxx> +#include <osl/diagnose.h> + +using namespace connectivity; +using namespace connectivity::file; + +ORowSetValue OOp_DayOfWeek::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + sal_Int32 nRet = 0; + css::util::Date aD = lhs; + Date aDate(aD.Day,aD.Month,aD.Year); + DayOfWeek eDayOfWeek = aDate.GetDayOfWeek(); + switch(eDayOfWeek) + { + case MONDAY: + nRet = 2; + break; + case TUESDAY: + nRet = 3; + break; + case WEDNESDAY: + nRet = 4; + break; + case THURSDAY: + nRet = 5; + break; + case FRIDAY: + nRet = 6; + break; + case SATURDAY: + nRet = 7; + break; + case SUNDAY: + nRet = 1; + break; + default: + OSL_FAIL("Error in enum values for date"); + } + return nRet; +} + +ORowSetValue OOp_DayOfMonth::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + css::util::Date aD = lhs; + return static_cast<sal_Int16>(aD.Day); +} + +ORowSetValue OOp_DayOfYear::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + css::util::Date aD = lhs; + Date aDate(aD.Day,aD.Month,aD.Year); + return static_cast<sal_Int16>(aDate.GetDayOfYear()); +} + +ORowSetValue OOp_Month::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + css::util::Date aD = lhs; + return static_cast<sal_Int16>(aD.Month); +} + +ORowSetValue OOp_DayName::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + OUString sRet; + css::util::Date aD = lhs; + Date aDate(aD.Day,aD.Month,aD.Year); + DayOfWeek eDayOfWeek = aDate.GetDayOfWeek(); + switch(eDayOfWeek) + { + case MONDAY: + sRet = "Monday"; + break; + case TUESDAY: + sRet = "Tuesday"; + break; + case WEDNESDAY: + sRet = "Wednesday"; + break; + case THURSDAY: + sRet = "Thursday"; + break; + case FRIDAY: + sRet = "Friday"; + break; + case SATURDAY: + sRet = "Saturday"; + break; + case SUNDAY: + sRet = "Sunday"; + break; + default: + OSL_FAIL("Error in enum values for date"); + } + return sRet; +} + +ORowSetValue OOp_MonthName::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + OUString sRet; + css::util::Date aD = lhs; + switch(aD.Month) + { + case 1: + sRet = "January"; + break; + case 2: + sRet = "February"; + break; + case 3: + sRet = "March"; + break; + case 4: + sRet = "April"; + break; + case 5: + sRet = "May"; + break; + case 6: + sRet = "June"; + break; + case 7: + sRet = "July"; + break; + case 8: + sRet = "August"; + break; + case 9: + sRet = "September"; + break; + case 10: + sRet = "October"; + break; + case 11: + sRet = "November"; + break; + case 12: + sRet = "December"; + break; + } + return sRet; +} + +ORowSetValue OOp_Quarter::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + sal_Int32 nRet = 1; + css::util::Date aD = lhs; + if ( aD.Month >= 4 && aD.Month < 7 ) + nRet = 2; + else if ( aD.Month >= 7 && aD.Month < 10 ) + nRet = 3; + else if ( aD.Month >= 10 && aD.Month <= 12 ) + nRet = 4; + return nRet; +} + +ORowSetValue OOp_Week::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( lhs.empty() || lhs.size() > 2 ) + return ORowSetValue(); + + size_t nSize = lhs.size(); + + css::util::Date aD = lhs[nSize-1]; + Date aDate(aD.Day,aD.Month,aD.Year); + + sal_Int16 nStartDay = SUNDAY; + if ( nSize == 2 && !lhs[0].isNull() ) + nStartDay = lhs[0]; + + return static_cast<sal_Int16>(aDate.GetWeekOfYear(static_cast<DayOfWeek>(nStartDay))); +} + +ORowSetValue OOp_Year::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + css::util::Date aD = lhs; + return aD.Year; +} + +ORowSetValue OOp_Hour::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + css::util::Time aT = lhs; + return static_cast<sal_Int16>(aT.Hours); +} + +ORowSetValue OOp_Minute::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + css::util::Time aT = lhs; + return static_cast<sal_Int16>(aT.Minutes); +} + +ORowSetValue OOp_Second::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + css::util::Time aT = lhs; + return static_cast<sal_Int16>(aT.Seconds); +} + +ORowSetValue OOp_CurDate::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( !lhs.empty() ) + return ORowSetValue(); + + Date aCurDate( Date::SYSTEM ); + return aCurDate.GetUNODate(); +} + +ORowSetValue OOp_CurTime::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( !lhs.empty() ) + return ORowSetValue(); + + tools::Time aCurTime( tools::Time::SYSTEM ); + return aCurTime.GetUNOTime(); +} + +ORowSetValue OOp_Now::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( !lhs.empty() ) + return ORowSetValue(); + + DateTime aCurTime( DateTime::SYSTEM ); + return aCurTime.GetUNODateTime(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FDriver.cxx b/connectivity/source/drivers/file/FDriver.cxx new file mode 100644 index 000000000..c2956adc2 --- /dev/null +++ b/connectivity/source/drivers/file/FDriver.cxx @@ -0,0 +1,227 @@ +/* -*- 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 <file/FDriver.hxx> +#include <file/FConnection.hxx> +#include <file/fcode.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + + +using namespace connectivity::file; +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::sdbcx; +using namespace com::sun::star::container; + +OFileDriver::OFileDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) + : ODriver_BASE(m_aMutex) + ,m_xContext(_rxContext) +{ +} + +void OFileDriver::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + + for (auto const& connection : m_xConnections) + { + Reference< XComponent > xComp(connection.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + } + m_xConnections.clear(); + + ODriver_BASE::disposing(); +} + +// static ServiceInfo + +OUString OFileDriver::getImplementationName_Static( ) +{ + return "com.sun.star.sdbc.driver.file.Driver"; +} + +Sequence< OUString > OFileDriver::getSupportedServiceNames_Static( ) +{ + return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" }; +} + + +OUString SAL_CALL OFileDriver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL OFileDriver::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +Sequence< OUString > SAL_CALL OFileDriver::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + + +Reference< XConnection > SAL_CALL OFileDriver::connect( const OUString& url, const Sequence< PropertyValue >& info ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODriver_BASE::rBHelper.bDisposed); + + OConnection* pCon = new OConnection(this); + Reference< XConnection > xCon = pCon; + pCon->construct(url,info); + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + + return xCon; +} + +sal_Bool SAL_CALL OFileDriver::acceptsURL( const OUString& url ) +{ + return url.startsWith("sdbc:file:"); +} + +Sequence< DriverPropertyInfo > SAL_CALL OFileDriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) +{ + if ( acceptsURL(url) ) + { + std::vector< DriverPropertyInfo > aDriverInfo; + + Sequence< OUString > aBoolean(2); + aBoolean[0] = "0"; + aBoolean[1] = "1"; + + aDriverInfo.push_back(DriverPropertyInfo( + "CharSet" + ,"CharSet of the database." + ,false + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "Extension" + ,"Extension of the file format." + ,false + ,".*" + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "ShowDeleted" + ,"Display inactive records." + ,false + ,"0" + ,aBoolean) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "EnableSQL92Check" + ,"Use SQL92 naming constraints." + ,false + ,"0" + ,aBoolean) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "UseRelativePath" + ,"Handle the connection url as relative path." + ,false + ,"0" + ,aBoolean) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "URL" + ,"The URL of the database document which is used to create an absolute path." + ,false + ,OUString() + ,Sequence< OUString >()) + ); + return Sequence< DriverPropertyInfo >(aDriverInfo.data(),aDriverInfo.size()); + } // if ( acceptsURL(url) ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } // if ( ! acceptsURL(url) ) + return Sequence< DriverPropertyInfo >(); +} + +sal_Int32 SAL_CALL OFileDriver::getMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL OFileDriver::getMinorVersion( ) +{ + return 0; +} + + +// XDataDefinitionSupplier +Reference< XTablesSupplier > SAL_CALL OFileDriver::getDataDefinitionByConnection( const Reference< css::sdbc::XConnection >& connection ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODriver_BASE::rBHelper.bDisposed); + + Reference< XTablesSupplier > xTab; + Reference< css::lang::XUnoTunnel> xTunnel(connection,UNO_QUERY); + if(xTunnel.is()) + { + OConnection* pSearchConnection = reinterpret_cast< OConnection* >( xTunnel->getSomething(OConnection::getUnoTunnelId()) ); + OConnection* pConnection = nullptr; + for (auto const& elem : m_xConnections) + { + if (static_cast<OConnection*>( Reference< XConnection >::query(elem.get().get()).get() ) == pSearchConnection) + { + pConnection = pSearchConnection; + break; + } + } + + if(pConnection) + xTab = pConnection->createCatalog(); + } + return xTab; +} + + +Reference< XTablesSupplier > SAL_CALL OFileDriver::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info ) +{ + if ( ! acceptsURL(url) ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + return getDataDefinitionByConnection(connect(url,info)); +} + + +OOperandAttr::OOperandAttr(sal_uInt16 _nPos,const Reference< XPropertySet>& _xColumn) + : OOperandRow(_nPos,::comphelper::getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))) +{ +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FNoException.cxx b/connectivity/source/drivers/file/FNoException.cxx new file mode 100644 index 000000000..7c26081da --- /dev/null +++ b/connectivity/source/drivers/file/FNoException.cxx @@ -0,0 +1,102 @@ +/* -*- 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 <file/FCatalog.hxx> +#include <file/fcomp.hxx> +#include <file/fanalyzer.hxx> +#include <file/FResultSet.hxx> +#include <file/FPreparedStatement.hxx> +#include <connectivity/FValue.hxx> +#include <tools/debug.hxx> +#include <TKeyValue.hxx> + +using namespace connectivity; +using namespace connectivity::file; + +void OFileCatalog::refreshViews() +{} +void OFileCatalog::refreshGroups() +{} +void OFileCatalog::refreshUsers() +{ +} + +OPredicateInterpreter::~OPredicateInterpreter() +{ + while(!m_aStack.empty()) + { + delete m_aStack.top(); + m_aStack.pop(); + } + // m_aStack.clear(); +} + +void OPredicateCompiler::Clean() +{ + m_aCodeList.clear(); +} + +void OSQLAnalyzer::bindParameterRow(OValueRefRow const & _pRow) +{ + OCodeList& rCodeList = m_aCompiler->m_aCodeList; + for (auto const& code : rCodeList) + { + OOperandParam* pParam = dynamic_cast<OOperandParam*>(code.get()); + if ( pParam ) + pParam->bindValue(_pRow); + } +} + +void OPreparedStatement::scanParameter(OSQLParseNode* pParseNode,std::vector< OSQLParseNode*>& _rParaNodes) +{ + DBG_ASSERT(pParseNode != nullptr,"OResultSet: internal error: invalid ParseNode"); + + // found parameter Name-Rule? + if (SQL_ISRULE(pParseNode,parameter)) + { + DBG_ASSERT(pParseNode->count() >= 1,"OResultSet: faulty Parse Tree"); + DBG_ASSERT(pParseNode->getChild(0)->getNodeType() == SQLNodeType::Punctuation,"OResultSet: faulty Parse Tree"); + + _rParaNodes.push_back(pParseNode); + // Further descend not necessary + return; + } + + // Further descend in Parse Tree + for (size_t i = 0; i < pParseNode->count(); i++) + scanParameter(pParseNode->getChild(i),_rParaNodes); +} + +std::unique_ptr<OKeyValue> OResultSet::GetOrderbyKeyValue(OValueRefRow const & _rRow) +{ + sal_uInt32 nBookmarkValue = std::abs(static_cast<sal_Int32>((*_rRow)[0]->getValue())); + + std::unique_ptr<OKeyValue> pKeyValue = OKeyValue::createKeyValue(nBookmarkValue); + + for (auto const& elem : m_aOrderbyColumnNumber) + { + OSL_ENSURE(elem < static_cast<sal_Int32>(_rRow->size()),"Invalid index for orderkey values!"); + pKeyValue->pushKey(new ORowSetValueDecorator((*_rRow)[elem]->getValue())); + } + + return pKeyValue; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FNumericFunctions.cxx b/connectivity/source/drivers/file/FNumericFunctions.cxx new file mode 100644 index 000000000..d2188cbbc --- /dev/null +++ b/connectivity/source/drivers/file/FNumericFunctions.cxx @@ -0,0 +1,243 @@ +/* -*- 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 <cmath> +#include <file/FNumericFunctions.hxx> +#include <rtl/math.hxx> + +using namespace connectivity; +using namespace connectivity::file; + +static const double fPi = 3.14159265358979323846; + +ORowSetValue OOp_Abs::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + double nVal(lhs); + if ( nVal < 0 ) + nVal *= -1.0; + return fabs(nVal); +} + +ORowSetValue OOp_Sign::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + sal_Int32 nRet = 0; + double nVal(lhs); + if ( nVal < 0 ) + nRet = -1; + else if ( nVal > 0 ) + nRet = 1; + + return nRet; +} + +ORowSetValue OOp_Mod::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const +{ + if ( lhs.isNull() || rhs.isNull() ) + return ORowSetValue(); + + return fmod(static_cast<double>(lhs),static_cast<double>(rhs)); +} + +ORowSetValue OOp_Floor::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return floor(static_cast<double>(lhs)); +} + +ORowSetValue OOp_Ceiling::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + double nVal(lhs); + return ceil(nVal); +} + +ORowSetValue OOp_Round::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( lhs.empty() || lhs.size() > 2 ) + return ORowSetValue(); + + size_t nSize = lhs.size(); + double nVal = lhs[nSize-1]; + + sal_Int32 nDec = 0; + if ( nSize == 2 && !lhs[0].isNull() ) + nDec = lhs[0]; + return ::rtl::math::round(nVal,nDec); +} + +ORowSetValue OOp_Exp::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + double nVal(lhs); + return exp(nVal); +} + +ORowSetValue OOp_Ln::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() || static_cast<double>(lhs) < 0.0 ) + return lhs; + + double nVal(lhs); + nVal = log(nVal); + if ( std::isnan(nVal) ) + return ORowSetValue(); + return nVal; +} + +ORowSetValue OOp_Log::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( lhs.empty() || lhs.size() > 2 ) + return ORowSetValue(); + size_t nSize = lhs.size(); + double nVal = log( static_cast<double>(lhs[nSize-1]) ); + + + if ( nSize == 2 && !lhs[0].isNull() ) + nVal /= log(static_cast<double>(lhs[0])); + + if ( std::isnan(nVal) ) + return ORowSetValue(); + return nVal; +} + +ORowSetValue OOp_Log10::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() || static_cast<double>(lhs) < 0.0 ) + return lhs; + + double nVal = log(static_cast<double>(lhs)); + if ( std::isnan(nVal) ) + return ORowSetValue(); + nVal /= log(10.0); + return nVal; +} + +ORowSetValue OOp_Pow::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const +{ + if ( lhs.isNull() || rhs.isNull() ) + return lhs; + + return pow(static_cast<double>(lhs),static_cast<double>(rhs)); +} + +ORowSetValue OOp_Sqrt::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + double nVal = sqrt(static_cast<double>(lhs)); + if ( std::isnan(nVal) ) + return ORowSetValue(); + return nVal; +} + +ORowSetValue OOp_Pi::operate(const std::vector<ORowSetValue>& /*lhs*/) const +{ + return fPi; +} + +ORowSetValue OOp_Cos::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return cos(static_cast<double>(lhs)); +} + +ORowSetValue OOp_Sin::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return sin(static_cast<double>(lhs)); +} + +ORowSetValue OOp_Tan::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return tan(static_cast<double>(lhs)); +} + +ORowSetValue OOp_ACos::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return acos(static_cast<double>(lhs)); +} + +ORowSetValue OOp_ASin::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return asin(static_cast<double>(lhs)); +} + +ORowSetValue OOp_ATan::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return atan(static_cast<double>(lhs)); +} + +ORowSetValue OOp_ATan2::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const +{ + if ( lhs.isNull() || rhs.isNull() ) + return lhs; + + return atan2(static_cast<double>(lhs),static_cast<double>(rhs)); +} + +ORowSetValue OOp_Degrees::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + double nLhs = lhs; + return nLhs*180*(1.0/fPi); +} + +ORowSetValue OOp_Radians::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + double nLhs = lhs; + return nLhs*fPi*(1.0/180.0); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FPreparedStatement.cxx b/connectivity/source/drivers/file/FPreparedStatement.cxx new file mode 100644 index 000000000..fc5b81923 --- /dev/null +++ b/connectivity/source/drivers/file/FPreparedStatement.cxx @@ -0,0 +1,554 @@ +/* -*- 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 <osl/diagnose.h> +#include <file/FPreparedStatement.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <file/FResultSetMetaData.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/sequence.hxx> +#include <connectivity/dbconversion.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/PColumn.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <strings.hrc> + +using namespace connectivity; +using namespace comphelper; +using namespace ::dbtools; +using namespace connectivity::file; +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star; + +IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbc.driver.file.PreparedStatement","com.sun.star.sdbc.PreparedStatement"); + +OPreparedStatement::OPreparedStatement( OConnection* _pConnection) + : OStatement_BASE2( _pConnection ) +{ +} + + +OPreparedStatement::~OPreparedStatement() +{ +} + + +void OPreparedStatement::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + OStatement_BASE2::disposing(); + + m_xParamColumns = nullptr; + m_xMetaData.clear(); + if(m_aParameterRow.is()) + { + m_aParameterRow->clear(); + m_aParameterRow = nullptr; + } +} + +void OPreparedStatement::construct(const OUString& sql) +{ + OStatement_Base::construct(sql); + + m_aParameterRow = new OValueRefVector(); + m_aParameterRow->push_back(new ORowSetValueDecorator(sal_Int32(0)) ); + + Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY); + + if ( m_aSQLIterator.getStatementType() == OSQLStatementType::Select ) + m_xParamColumns = m_aSQLIterator.getParameters(); + else + { + m_xParamColumns = new OSQLColumns(); + // describe all parameters need for the resultset + describeParameter(); + } + + OValueRefRow aTemp; + OResultSet::setBoundedColumns(m_aEvaluateRow,aTemp,m_xParamColumns,xNames,false,m_xDBMetaData,m_aColMapping); +} + +rtl::Reference<OResultSet> OPreparedStatement::makeResultSet() +{ + closeResultSet(); + + rtl::Reference<OResultSet> xResultSet(createResultSet()); + m_xResultSet = xResultSet.get(); + initializeResultSet(xResultSet.get()); + initResultSet(xResultSet.get()); + return xResultSet; +} + +Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType ) +{ + Any aRet = OStatement_BASE2::queryInterface(rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface( rType, + static_cast< XPreparedStatement*>(this), + static_cast< XParameters*>(this), + static_cast< XResultSetMetaDataSupplier*>(this)); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<XPreparedStatement>::get(), + cppu::UnoType<XParameters>::get(), + cppu::UnoType<XResultSetMetaDataSupplier>::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE2::getTypes()); +} + + +Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(m_aSQLIterator.getSelectColumns(),m_aSQLIterator.getTables().begin()->first,m_pTable.get()); + return m_xMetaData.get(); +} + + +void SAL_CALL OPreparedStatement::close( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + closeResultSet(); +} + + +sal_Bool SAL_CALL OPreparedStatement::execute( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + rtl::Reference<OResultSet> xRS(makeResultSet()); + // since we don't support the XMultipleResults interface, nobody will ever get that ResultSet... + if(xRS.is()) + xRS->dispose(); + + return m_aSQLIterator.getStatementType() == OSQLStatementType::Select; +} + + +sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + rtl::Reference<OResultSet> xRS(makeResultSet()); + if(xRS.is()) + { + const sal_Int32 res(xRS->getRowCountResult()); + // nobody will ever get that ResultSet... + xRS->dispose(); + return res; + } + else + return 0; +} + + +void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ + setParameter(parameterIndex,x); +} + + +Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + return Reference< XConnection >(m_pConnection.get()); +} + + +Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + return makeResultSet().get(); +} + + +void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) +{ + setParameter(parameterIndex,static_cast<bool>(x)); +} + +void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x ) +{ + setParameter(parameterIndex,x); +} + + +void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const util::Date& aData ) +{ + setParameter(parameterIndex,DBTypeConversion::toDouble(aData)); +} + +void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const util::Time& aVal ) +{ + setParameter(parameterIndex,DBTypeConversion::toDouble(aVal)); +} + + +void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const util::DateTime& aVal ) +{ + setParameter(parameterIndex,DBTypeConversion::toDouble(aVal)); +} + + +void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) +{ + setParameter(parameterIndex,x); +} + + +void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) +{ + setParameter(parameterIndex,x); +} + + +void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) +{ + setParameter(parameterIndex,x); +} + + +void SAL_CALL OPreparedStatement::setLong( sal_Int32 /*parameterIndex*/, sal_Int64 /*aVal*/ ) +{ + throwFeatureNotImplementedSQLException( "XParameters::setLong", *this ); +} + + +void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkAndResizeParameters(parameterIndex); + + if ( m_aAssignValues.is() ) + (*m_aAssignValues)[m_aParameterIndexes[parameterIndex]]->setNull(); + else + (*m_aParameterRow)[parameterIndex]->setNull(); +} + + +void SAL_CALL OPreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ ) +{ + throwFeatureNotImplementedSQLException( "XParameters::setClob", *this ); +} + + +void SAL_CALL OPreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ ) +{ + throwFeatureNotImplementedSQLException( "XParameters::setBlob", *this ); +} + + +void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ ) +{ + throwFeatureNotImplementedSQLException( "XParameters::setArray", *this ); +} + + +void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ ) +{ + throwFeatureNotImplementedSQLException( "XParameters::setRef", *this ); +} + + +void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) +{ + switch(sqlType) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + setString(parameterIndex,::comphelper::getString(x)); + break; + default: + ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); + break; + } +} + + +void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ ) +{ + setNull(parameterIndex,sqlType); +} + + +void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) +{ + if(!::dbtools::implSetObject(this,parameterIndex,x)) + { + const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution( + STR_UNKNOWN_PARA_TYPE, + "$position$", OUString::number(parameterIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } + // setObject (parameterIndex, x, sqlType, 0); +} + + +void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) +{ + setParameter(parameterIndex,x); +} + + +void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) +{ + setParameter(parameterIndex,x); +} + + +void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + setBinaryStream(parameterIndex,x,length ); +} + + +void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + if(!x.is()) + ::dbtools::throwFunctionSequenceException(*this); + + Sequence<sal_Int8> aSeq; + x->readBytes(aSeq,length); + setParameter(parameterIndex,aSeq); +} + + +void SAL_CALL OPreparedStatement::clearParameters( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + m_aParameterRow->clear(); + m_aParameterRow->push_back(new ORowSetValueDecorator(sal_Int32(0)) ); +} + +OResultSet* OPreparedStatement::createResultSet() +{ + return new OResultSet(this,m_aSQLIterator); +} + +void OPreparedStatement::initResultSet(OResultSet *pResultSet) +{ + // check if we got enough parameters + if ( (m_aParameterRow.is() && ( m_aParameterRow->size() -1 ) < m_xParamColumns->size()) || + (m_xParamColumns.is() && !m_aParameterRow.is() && !m_aParameterRow->empty()) ) + m_pConnection->throwGenericSQLException(STR_INVALID_PARA_COUNT,*this); + + pResultSet->OpenImpl(); + pResultSet->setMetaData(getMetaData()); +} + +void SAL_CALL OPreparedStatement::acquire() throw() +{ + OStatement_BASE2::acquire(); +} + +void SAL_CALL OPreparedStatement::release() throw() +{ + OStatement_BASE2::release(); +} + +void OPreparedStatement::checkAndResizeParameters(sal_Int32 parameterIndex) +{ + ::connectivity::checkDisposed(OStatement_BASE::rBHelper.bDisposed); + if ( m_aAssignValues.is() && (parameterIndex < 1 || parameterIndex >= static_cast<sal_Int32>(m_aParameterIndexes.size())) ) + throwInvalidIndexException(*this); + else if ( static_cast<sal_Int32>(m_aParameterRow->size()) <= parameterIndex ) + { + sal_Int32 i = m_aParameterRow->size(); + m_aParameterRow->resize(parameterIndex+1); + for ( ; i <= parameterIndex; ++i) + { + if ( !(*m_aParameterRow)[i].is() ) + (*m_aParameterRow)[i] = new ORowSetValueDecorator; + } + } +} + +void OPreparedStatement::setParameter(sal_Int32 parameterIndex, const ORowSetValue& x) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkAndResizeParameters(parameterIndex); + + if(m_aAssignValues.is()) + *(*m_aAssignValues)[m_aParameterIndexes[parameterIndex]] = x; + else + *((*m_aParameterRow)[parameterIndex]) = x; +} + +sal_uInt32 OPreparedStatement::AddParameter(OSQLParseNode const * pParameter, const Reference<XPropertySet>& _xCol) +{ + OSL_ENSURE(SQL_ISRULE(pParameter,parameter),"OResultSet::AddParameter: Argument is not a parameter"); + OSL_ENSURE(pParameter->count() > 0,"OResultSet: Error in Parse Tree"); + + OUString sParameterName; + // set up Parameter-Column: + sal_Int32 eType = DataType::VARCHAR; + sal_uInt32 nPrecision = 255; + sal_Int32 nScale = 0; + sal_Int32 nNullable = ColumnValue::NULLABLE; + + if (_xCol.is()) + { + // Use type, precision, scale ... from the given column, + // because this Column will get a value assigned or + // with this Column the value will be compared. + _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= eType; + _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nPrecision; + _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale; + _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNullable; + _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sParameterName; + } + + Reference<XPropertySet> xParaColumn = new connectivity::parse::OParseColumn(sParameterName + ,OUString() + ,OUString() + ,OUString() + ,nNullable + ,nPrecision + ,nScale + ,eType + ,false + ,false + ,m_aSQLIterator.isCaseSensitive() + ,OUString() + ,OUString() + ,OUString()); + m_xParamColumns->push_back(xParaColumn); + return m_xParamColumns->size(); +} + +void OPreparedStatement::describeColumn(OSQLParseNode const * _pParameter, OSQLParseNode const * _pNode,const OSQLTable& _xTable) +{ + Reference<XPropertySet> xProp; + if(SQL_ISRULE(_pNode,column_ref)) + { + OUString sColumnName,sTableRange; + m_aSQLIterator.getColumnRange(_pNode,sColumnName,sTableRange); + if ( !sColumnName.isEmpty() ) + { + Reference<XNameAccess> xNameAccess = _xTable->getColumns(); + if(xNameAccess->hasByName(sColumnName)) + xNameAccess->getByName(sColumnName) >>= xProp; + AddParameter(_pParameter,xProp); + } + } + // else + // AddParameter(_pParameter,xProp); +} + +void OPreparedStatement::describeParameter() +{ + std::vector< OSQLParseNode*> aParseNodes; + scanParameter(m_pParseTree,aParseNodes); + if ( aParseNodes.empty() ) + return; + + // m_xParamColumns = new OSQLColumns(); + const OSQLTables& rTabs = m_aSQLIterator.getTables(); + if( !rTabs.empty() ) + { + OSQLTable xTable = rTabs.begin()->second; + for (auto const& parseNode : aParseNodes) + { + describeColumn(parseNode,parseNode->getParent()->getChild(0),xTable); + } + } +} +void OPreparedStatement::initializeResultSet(OResultSet* pRS) +{ + OStatement_Base::initializeResultSet(pRS); + + // Substitute parameter (AssignValues and criteria): + if (m_xParamColumns->empty()) + return; + + // begin with AssignValues + sal_uInt16 nParaCount=0; // gives the current number of previously set Parameters + + // search for parameters to be substituted: + size_t nCount = m_aAssignValues.is() ? m_aAssignValues->size() : 1; // 1 is important for the Criteria + for (size_t j = 1; j < nCount; j++) + { + sal_uInt32 nParameter = (*m_aAssignValues).getParameterIndex(j); + if (nParameter == SQL_NO_PARAMETER) + continue; // this AssignValue is no Parameter + + ++nParaCount; // now the Parameter is valid + } + + if (m_aParameterRow.is() && (m_xParamColumns->size()+1) != m_aParameterRow->size() ) + { + sal_Int32 i = m_aParameterRow->size(); + sal_Int32 nParamColumns = m_xParamColumns->size()+1; + m_aParameterRow->resize(nParamColumns); + for ( ;i < nParamColumns; ++i ) + { + if ( !(*m_aParameterRow)[i].is() ) + (*m_aParameterRow)[i] = new ORowSetValueDecorator; + } + } + if (m_aParameterRow.is() && nParaCount < m_aParameterRow->size() ) + m_pSQLAnalyzer->bindParameterRow(m_aParameterRow); +} + +void OPreparedStatement::parseParamterElem(const OUString& _sColumnName, OSQLParseNode* pRow_Value_Constructor_Elem) +{ + Reference<XPropertySet> xCol; + m_xColNames->getByName(_sColumnName) >>= xCol; + sal_Int32 nParameter = -1; + if(m_xParamColumns.is()) + { + OSQLColumns::const_iterator aIter = find(m_xParamColumns->begin(),m_xParamColumns->end(),_sColumnName,::comphelper::UStringMixEqual(m_pTable->isCaseSensitive())); + if(aIter != m_xParamColumns->end()) + nParameter = m_xParamColumns->size() - (m_xParamColumns->end() - aIter) + 1;// +1 because the rows start at 1 + } + if(nParameter == -1) + nParameter = AddParameter(pRow_Value_Constructor_Elem,xCol); + // Save number of parameter in the variable: + SetAssignValue(_sColumnName, OUString(), true, nParameter); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FResultSet.cxx b/connectivity/source/drivers/file/FResultSet.cxx new file mode 100644 index 000000000..d7f3d6bd2 --- /dev/null +++ b/connectivity/source/drivers/file/FResultSet.cxx @@ -0,0 +1,1595 @@ +/* -*- 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 <file/FResultSet.hxx> +#include <sqlbison.hxx> +#include <file/FResultSetMetaData.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/propshlp.hxx> +#include <sal/log.hxx> +#include <iterator> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbcx/XIndexesSupplier.hpp> + +#include <algorithm> +#include <connectivity/dbexception.hxx> +#include <comphelper/types.hxx> +#include <resource/sharedresources.hxx> +#include <strings.hrc> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::file; +using namespace ::cppu; +using namespace dbtools; +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::sdbcx; +using namespace com::sun::star::container; + +namespace +{ + void lcl_throwError(const char* pErrorId, const css::uno::Reference< css::uno::XInterface>& _xContext) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(pErrorId); + ::dbtools::throwGenericSQLException(sMessage ,_xContext); + } +} + +IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.drivers.file.ResultSet","com.sun.star.sdbc.ResultSet"); + +OResultSet::OResultSet(OStatement_Base* pStmt,OSQLParseTreeIterator& _aSQLIterator) : OResultSet_BASE(m_aMutex) + ,::comphelper::OPropertyContainer(OResultSet_BASE::rBHelper) + ,m_aSkipDeletedSet(this) + ,m_pParseTree(pStmt->getParseTree()) + ,m_pSQLAnalyzer(nullptr) + ,m_aSQLIterator(_aSQLIterator) + ,m_nFetchSize(0) + ,m_nResultSetType(ResultSetType::SCROLL_INSENSITIVE) + ,m_nFetchDirection(FetchDirection::FORWARD) + ,m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE) + ,m_xStatement(*pStmt) + ,m_nRowPos(-1) + ,m_nFilePos(0) + ,m_nLastVisitedPos(-1) + ,m_nRowCountResult(-1) + ,m_nColumnCount(0) + ,m_bWasNull(false) + ,m_bInserted(false) + ,m_bRowUpdated(false) + ,m_bRowInserted(false) + ,m_bRowDeleted(false) + ,m_bShowDeleted(pStmt->getOwnConnection()->showDeleted()) + ,m_bIsCount(false) +{ + osl_atomic_increment( &m_refCount ); + m_bIsCount = (m_pParseTree && + m_pParseTree->count() > 2 && + SQL_ISRULE(m_pParseTree->getChild(2),scalar_exp_commalist) && + SQL_ISRULE(m_pParseTree->getChild(2)->getChild(0),derived_column) && + SQL_ISRULE(m_pParseTree->getChild(2)->getChild(0)->getChild(0),general_set_fct) && + m_pParseTree->getChild(2)->getChild(0)->getChild(0)->count() == 4 + ); + + m_nResultSetConcurrency = isCount() ? ResultSetConcurrency::READ_ONLY : ResultSetConcurrency::UPDATABLE; + construct(); + m_aSkipDeletedSet.SetDeletedVisible(m_bShowDeleted); + osl_atomic_decrement( &m_refCount ); +} + + +OResultSet::~OResultSet() +{ + osl_atomic_increment( &m_refCount ); + disposing(); +} + +void OResultSet::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 OResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + m_xStatement.clear(); + m_xMetaData.clear(); + m_pParseTree = nullptr; + m_xColNames.clear(); + m_xColumns = nullptr; + m_xColsIdx.clear(); + + Reference<XComponent> xComp = m_pTable.get(); + if ( xComp.is() ) + xComp->removeEventListener(this); + m_pTable.clear(); + + m_pFileSet = nullptr; + m_pSortIndex.reset(); + + if(m_aInsertRow.is()) + m_aInsertRow->clear(); + + m_aSkipDeletedSet.clear(); +} + +Any SAL_CALL OResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OResultSet::getTypes( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(), + cppu::UnoType<css::beans::XPropertySet>::get(), + cppu::UnoType<css::beans::XPropertySet>::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),OResultSet_BASE::getTypes()); +} + + +sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_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 ); + assert(false); + return 0; // Never reached +} + +const ORowSetValue& OResultSet::getValue(sal_Int32 columnIndex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + checkIndex(columnIndex ); + + + m_bWasNull = (*m_aSelectRow)[columnIndex]->getValue().isNull(); + return *(*m_aSelectRow)[columnIndex]; +} + +void OResultSet::checkIndex(sal_Int32 columnIndex ) +{ + if ( columnIndex <= 0 + || columnIndex >= m_nColumnCount ) + ::dbtools::throwInvalidIndexException(*this); +} + +Reference< css::io::XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + +Reference< css::io::XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 columnIndex ) +{ + return bool(getValue(columnIndex)); +} + + +sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +css::util::Date SAL_CALL OResultSet::getDate( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +double SAL_CALL OResultSet::getDouble( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +float SAL_CALL OResultSet::getFloat( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +sal_Int32 SAL_CALL OResultSet::getRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + OSL_ENSURE((m_bShowDeleted || !m_aRow->isDeleted()),"getRow called for deleted row"); + + return m_aSkipDeletedSet.getMappedPosition((*m_aRow)[0]->getValue()); +} + + +sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(m_xColumns,m_aSQLIterator.getTables().begin()->first,m_pTable.get()); + return m_xMetaData; +} + +Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + +Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Any SAL_CALL OResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + return getValue(columnIndex).makeAny(); +} + + +sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + +OUString SAL_CALL OResultSet::getString( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + +css::util::Time SAL_CALL OResultSet::getTime( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + +css::util::DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + return getValue(columnIndex); +} + + +sal_Bool SAL_CALL OResultSet::isAfterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_nRowPos == sal_Int32(m_pFileSet->size()); +} + +sal_Bool SAL_CALL OResultSet::isFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_nRowPos == 0; +} + +sal_Bool SAL_CALL OResultSet::isLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_nRowPos == sal_Int32(m_pFileSet->size() - 1); +} + +void SAL_CALL OResultSet::beforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(first()) + previous(); +} + +void SAL_CALL OResultSet::afterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(last()) + next(); +} + + +void SAL_CALL OResultSet::close( ) +{ + dispose(); +} + + +sal_Bool SAL_CALL OResultSet::first( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::FIRST,1,true); +} + + +sal_Bool SAL_CALL OResultSet::last( ) +{ + // here I know definitely that I stand on the last record + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::LAST,1,true); +} + +sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::ABSOLUTE1,row,true); +} + +sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::RELATIVE1,row,true); +} + +sal_Bool SAL_CALL OResultSet::previous( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::PRIOR,0,true); +} + +Reference< XInterface > SAL_CALL OResultSet::getStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_xStatement; +} + + +sal_Bool SAL_CALL OResultSet::rowDeleted( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_bRowDeleted; +} + +sal_Bool SAL_CALL OResultSet::rowInserted( ) +{ ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_bRowInserted; +} + +sal_Bool SAL_CALL OResultSet::rowUpdated( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_bRowUpdated; +} + + +sal_Bool SAL_CALL OResultSet::isBeforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_nRowPos == -1; +} + +sal_Bool SAL_CALL OResultSet::next( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::NEXT,1,true); +} + + +sal_Bool SAL_CALL OResultSet::wasNull( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + + +void SAL_CALL OResultSet::cancel( ) +{ +} + +void SAL_CALL OResultSet::clearWarnings( ) +{ +} + +Any SAL_CALL OResultSet::getWarnings( ) +{ + return Any(); +} + +void SAL_CALL OResultSet::insertRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(!m_bInserted || !m_pTable.is()) + throwFunctionSequenceException(*this); + + // we know that we append new rows at the end + // so we have to know where the end is + (void)m_aSkipDeletedSet.skipDeleted(IResultSetHelper::LAST,1,false); + m_bRowInserted = m_pTable->InsertRow(*m_aInsertRow, m_xColsIdx); + if(m_bRowInserted && m_pFileSet.is()) + { + sal_Int32 nPos = (*m_aInsertRow)[0]->getValue(); + m_pFileSet->push_back(nPos); + *(*m_aInsertRow)[0] = sal_Int32(m_pFileSet->size()); + clearInsertRow(); + + m_aSkipDeletedSet.insertNewPosition((*m_aRow)[0]->getValue()); + } +} + +void SAL_CALL OResultSet::updateRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if(!m_pTable.is() || m_pTable->isReadOnly()) + lcl_throwError(STR_TABLE_READONLY,*this); + + m_bRowUpdated = m_pTable->UpdateRow(*m_aInsertRow, m_aRow,m_xColsIdx); + *(*m_aInsertRow)[0] = static_cast<sal_Int32>((*m_aRow)[0]->getValue()); + + clearInsertRow(); +} + +void SAL_CALL OResultSet::deleteRow() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if(!m_pTable.is() || m_pTable->isReadOnly()) + lcl_throwError(STR_TABLE_READONLY,*this); + if (m_bShowDeleted) + lcl_throwError(STR_DELETE_ROW,*this); + if(m_aRow->isDeleted()) + lcl_throwError(STR_ROW_ALREADY_DELETED,*this); + + sal_Int32 nPos = static_cast<sal_Int32>((*m_aRow)[0]->getValue()); + m_bRowDeleted = m_pTable->DeleteRow(*m_xColumns); + if(m_bRowDeleted && m_pFileSet.is()) + { + m_aRow->setDeleted(true); + // don't touch the m_pFileSet member here + m_aSkipDeletedSet.deletePosition(nPos); + } +} + +void SAL_CALL OResultSet::cancelRowUpdates( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_bInserted = false; + m_bRowUpdated = false; + m_bRowInserted = false; + m_bRowDeleted = false; + + if(m_aInsertRow.is()) + { + OValueRefVector::iterator aIter = m_aInsertRow->begin()+1; + for(;aIter != m_aInsertRow->end();++aIter) + { + (*aIter)->setBound(false); + (*aIter)->setNull(); + } + } +} + + +void SAL_CALL OResultSet::moveToInsertRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if(!m_pTable.is() || m_pTable->isReadOnly()) + lcl_throwError(STR_TABLE_READONLY,*this); + + m_bInserted = true; + + OValueRefVector::iterator aIter = m_aInsertRow->begin()+1; + for(;aIter != m_aInsertRow->end();++aIter) + { + (*aIter)->setBound(false); + (*aIter)->setNull(); + } +} + + +void SAL_CALL OResultSet::moveToCurrentRow( ) +{ +} + +void OResultSet::updateValue(sal_Int32 columnIndex ,const ORowSetValue& x) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + checkIndex(columnIndex ); + columnIndex = mapColumn(columnIndex); + + (*m_aInsertRow)[columnIndex]->setBound(true); + *(*m_aInsertRow)[columnIndex] = x; +} + + +void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex ) +{ + ORowSetValue aEmpty; + updateValue(columnIndex,aEmpty); +} + + +void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) +{ + updateValue(columnIndex, static_cast<bool>(x)); +} + +void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateLong( sal_Int32 /*columnIndex*/, sal_Int64 /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::updateLong", *this ); +} + +void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if(!x.is()) + ::dbtools::throwFunctionSequenceException(*this); + + Sequence<sal_Int8> aSeq; + x->readBytes(aSeq,length); + updateValue(columnIndex,aSeq); +} + +void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + updateBinaryStream(columnIndex,x,length); +} + +void SAL_CALL OResultSet::refreshRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x ) +{ + if (!::dbtools::implUpdateObject(this, columnIndex, x)) + throw SQLException(); +} + + +void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ ) +{ + if (!::dbtools::implUpdateObject(this, columnIndex, x)) + throw SQLException(); +} + +IPropertyArrayHelper* OResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +IPropertyArrayHelper & OResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + + +bool OResultSet::ExecuteRow(IResultSetHelper::Movement eFirstCursorPosition, + sal_Int32 nFirstOffset, + bool bEvaluate, + bool bRetrieveData) +{ + OSL_ENSURE(m_pSQLAnalyzer,"OResultSet::ExecuteRow: Analyzer isn't set!"); + + // For further Fetch-Operations this information may possibly be changed ... + IResultSetHelper::Movement eCursorPosition = eFirstCursorPosition; + sal_Int32 nOffset = nFirstOffset; + + if (!m_pTable.is()) + return false; + + const OSQLColumns & rTableCols = *(m_pTable->getTableColumns()); + bool bHasRestriction = m_pSQLAnalyzer->hasRestriction(); +again: + + // protect from reading over the end when somebody is inserting while we are reading + // this method works only for dBase at the moment!!! + if (eCursorPosition == IResultSetHelper::NEXT && m_nFilePos == m_nLastVisitedPos) + { + return false; + } + + if (!m_pTable.is() || !m_pTable->seekRow(eCursorPosition, nOffset, m_nFilePos)) + { + return false; + } + + if (!bEvaluate) // If no evaluation runs, then just fill the results-row + { + m_pTable->fetchRow(m_aRow,rTableCols, bRetrieveData); + } + else + { + m_pTable->fetchRow(m_aEvaluateRow, rTableCols, bRetrieveData || bHasRestriction); + + if ( ( !m_bShowDeleted + && m_aEvaluateRow->isDeleted() + ) + || ( bHasRestriction + && !m_pSQLAnalyzer->evaluateRestriction() + ) + ) + { // Evaluate the next record + // delete current row in Keyset + if (m_pFileSet.is()) + { + OSL_ENSURE(eCursorPosition == IResultSetHelper::NEXT, "Wrong CursorPosition!"); + eCursorPosition = IResultSetHelper::NEXT; + nOffset = 1; + } + else if (eCursorPosition == IResultSetHelper::FIRST || + eCursorPosition == IResultSetHelper::NEXT || + eCursorPosition == IResultSetHelper::ABSOLUTE1) + { + eCursorPosition = IResultSetHelper::NEXT; + nOffset = 1; + } + else if (eCursorPosition == IResultSetHelper::LAST || + eCursorPosition == IResultSetHelper::PRIOR) + { + eCursorPosition = IResultSetHelper::PRIOR; + nOffset = 1; + } + else if (eCursorPosition == IResultSetHelper::RELATIVE1) + { + eCursorPosition = (nOffset >= 0) ? IResultSetHelper::NEXT : IResultSetHelper::PRIOR; + } + else + { + return false; + } + // Try again ... + goto again; + } + } + + // Evaluate may only be set, + // if the Keyset will be constructed further + if ( ( m_aSQLIterator.getStatementType() == OSQLStatementType::Select ) + && !isCount() + && bEvaluate + ) + { + if (m_pSortIndex) + { + std::unique_ptr<OKeyValue> pKeyValue = GetOrderbyKeyValue( m_aSelectRow ); + m_pSortIndex->AddKeyValue(std::move(pKeyValue)); + } + else if (m_pFileSet.is()) + { + sal_uInt32 nBookmarkValue = std::abs(static_cast<sal_Int32>((*m_aEvaluateRow)[0]->getValue())); + m_pFileSet->push_back(nBookmarkValue); + } + } + else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Update) + { + bool bOK = true; + if (bEvaluate) + { + // read the actual result-row + bOK = m_pTable->fetchRow(m_aEvaluateRow, *(m_pTable->getTableColumns()), true); + } + + if (bOK) + { + // just give the values to be changed: + if(!m_pTable->UpdateRow(*m_aAssignValues,m_aEvaluateRow, m_xColsIdx)) + return false; + } + } + else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Delete) + { + bool bOK = true; + if (bEvaluate) + { + bOK = m_pTable->fetchRow(m_aEvaluateRow, *(m_pTable->getTableColumns()), true); + } + if (bOK) + { + if(!m_pTable->DeleteRow(*m_xColumns)) + return false; + } + } + return true; +} + + +bool OResultSet::Move(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, bool bRetrieveData) +{ + sal_Int32 nTempPos = m_nRowPos; + + if (m_aSQLIterator.getStatementType() == OSQLStatementType::Select && + !isCount()) + { + if (!m_pFileSet.is()) //no Index available + { + // Normal FETCH + ExecuteRow(eCursorPosition,nOffset,false,bRetrieveData); + + // now set the bookmark for outside this is the logical pos and not the file pos + *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1); + } + else + { + switch(eCursorPosition) + { + case IResultSetHelper::NEXT: + ++m_nRowPos; + break; + case IResultSetHelper::PRIOR: + if (m_nRowPos >= 0) + --m_nRowPos; + break; + case IResultSetHelper::FIRST: + m_nRowPos = 0; + break; + case IResultSetHelper::LAST: + m_nRowPos = m_pFileSet->size() - 1; + break; + case IResultSetHelper::RELATIVE1: + m_nRowPos += nOffset; + break; + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::BOOKMARK: + if ( m_nRowPos == (nOffset -1) ) + return true; + m_nRowPos = nOffset -1; + break; + } + + // OffRange? + // The FileCursor is outside of the valid range, if: + // a.) m_nRowPos < 1 + // b.) a KeySet exists and m_nRowPos > m_pFileSet->size() + if (m_nRowPos < 0 || (m_pFileSet->isFrozen() && eCursorPosition != IResultSetHelper::BOOKMARK && m_nRowPos >= static_cast<sal_Int32>(m_pFileSet->size()) )) // && m_pFileSet->IsFrozen() + { + goto Error; + } + else + { + if (m_nRowPos < static_cast<sal_Int32>(m_pFileSet->size())) + { + // Fetch via Index + bool bOK = ExecuteRow(IResultSetHelper::BOOKMARK,(*m_pFileSet)[m_nRowPos],false,bRetrieveData); + if (!bOK) + goto Error; + + // now set the bookmark for outside + *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1); + if ( (bRetrieveData || m_pSQLAnalyzer->hasRestriction()) && m_pSQLAnalyzer->hasFunctions() ) + { + m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping); + } + } + else // Index must be further constructed + { + // set first on the last known row + if (m_pFileSet->empty()) + { + m_pTable->seekRow(IResultSetHelper::ABSOLUTE1, 0, m_nFilePos); + } + else + { + m_aFileSetIter = m_pFileSet->end()-1; + m_pTable->seekRow(IResultSetHelper::BOOKMARK, *m_aFileSetIter, m_nFilePos); + } + bool bOK = true; + // Determine the number of further Fetches + while (bOK && m_nRowPos >= static_cast<sal_Int32>(m_pFileSet->size())) + { + bOK = ExecuteRow(IResultSetHelper::NEXT,1,true, false);//bRetrieveData); + } + + if (bOK) + { + // read the results again + m_pTable->fetchRow(m_aRow, *(m_pTable->getTableColumns()), bRetrieveData); + + // now set the bookmark for outside + *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1); + + if ( (bRetrieveData || m_pSQLAnalyzer->hasRestriction()) && m_pSQLAnalyzer->hasFunctions() ) + { + m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping); + } + } + else if (!m_pFileSet->isFrozen()) // no valid record found + { + m_pFileSet->setFrozen(); + goto Error; + } + } + } + } + } + else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Select && isCount()) + { + // Fetch the COUNT(*) + switch (eCursorPosition) + { + case IResultSetHelper::NEXT: + ++m_nRowPos; + break; + case IResultSetHelper::PRIOR: + --m_nRowPos; + break; + case IResultSetHelper::FIRST: + m_nRowPos = 0; + break; + case IResultSetHelper::LAST: + m_nRowPos = 0; + break; + case IResultSetHelper::RELATIVE1: + m_nRowPos += nOffset; + break; + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::BOOKMARK: + m_nRowPos = nOffset - 1; + break; + } + + if ( m_nRowPos < 0 ) + goto Error; + else if (m_nRowPos == 0) + { + // put COUNT(*) in result-row + // (must be the first and only variable in the row) + if (m_aRow->size() >= 2) + { + *(*m_aRow)[1] = m_nRowCountResult; + *(*m_aRow)[0] = sal_Int32(1); + (*m_aRow)[1]->setBound(true); + (*m_aSelectRow)[1] = (*m_aRow)[1]; + } + } + else + { + m_nRowPos = 1; + return false; + } + } + else + // Fetch only possible at SELECT! + return false; + + return true; + +Error: + // is the Cursor positioned before the first row + // then the position will be maintained + if (nTempPos == -1) + m_nRowPos = nTempPos; + else + { + switch(eCursorPosition) + { + case IResultSetHelper::PRIOR: + case IResultSetHelper::FIRST: + m_nRowPos = -1; + break; + case IResultSetHelper::LAST: + case IResultSetHelper::NEXT: + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::RELATIVE1: + if (nOffset > 0) + m_nRowPos = m_pFileSet.is() ? static_cast<sal_Int32>(m_pFileSet->size()) : -1; + else if (nOffset < 0) + m_nRowPos = -1; + break; + case IResultSetHelper::BOOKMARK: + m_nRowPos = nTempPos; // last Position + } + } + return false; +} + +void OResultSet::sortRows() +{ + if (!m_pSQLAnalyzer->hasRestriction() && m_aOrderbyColumnNumber.size() == 1) + { + // is just one field given for sorting + // and this field is indexed, then the Index will be used + Reference<XIndexesSupplier> xIndexSup; + m_pTable->queryInterface(cppu::UnoType<XIndexesSupplier>::get()) >>= xIndexSup; + + Reference<XIndexAccess> xIndexes; + if(xIndexSup.is()) + { + xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY); + Reference<XPropertySet> xColProp; + if(m_aOrderbyColumnNumber[0] < xIndexes->getCount()) + { + xColProp.set(xIndexes->getByIndex(m_aOrderbyColumnNumber[0]),UNO_QUERY); + // iterate through the indexes to find the matching column + const sal_Int32 nCount = xIndexes->getCount(); + for(sal_Int32 i=0; i < nCount;++i) + { + Reference<XColumnsSupplier> xIndex(xIndexes->getByIndex(i),UNO_QUERY); + Reference<XNameAccess> xIndexCols = xIndex->getColumns(); + if(xIndexCols->hasByName(comphelper::getString(xColProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))))) + { + m_pFileSet = new OKeySet(); + + if(fillIndexValues(xIndex)) + return; + } + } + } + } + } + + OSortIndex::TKeyTypeVector eKeyType(m_aOrderbyColumnNumber.size()); + size_t i = 0; + for (auto const& elem : m_aOrderbyColumnNumber) + { + OSL_ENSURE(static_cast<sal_Int32>(m_aSelectRow->size()) > elem,"Invalid Index"); + switch ((*(m_aSelectRow->begin()+elem))->getValue().getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + eKeyType[i] = OKeyType::String; + break; + + case DataType::OTHER: + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BIT: + eKeyType[i] = OKeyType::Double; + break; + + // Other types aren't implemented (so they are always FALSE) + default: + eKeyType[i] = OKeyType::NONE; + SAL_WARN( "connectivity.drivers","OFILECursor::Execute: Data type not implemented"); + break; + } + (*m_aSelectRow)[elem]->setBound(true); + ++i; + } + + m_pSortIndex.reset(new OSortIndex(eKeyType,m_aOrderbyAscending)); + + while ( ExecuteRow( IResultSetHelper::NEXT, 1, false ) ) + { + (*m_aSelectRow)[0]->setValue( (*m_aRow)[0]->getValue() ); + if ( m_pSQLAnalyzer->hasFunctions() ) + m_pSQLAnalyzer->setSelectionEvaluationResult( m_aSelectRow, m_aColMapping ); + const sal_Int32 nBookmark = (*m_aRow->begin())->getValue(); + ExecuteRow( IResultSetHelper::BOOKMARK, nBookmark, true, false ); + } + + // create sorted Keyset + m_pFileSet = nullptr; + m_pFileSet = m_pSortIndex->CreateKeySet(); + m_pSortIndex.reset(); + // now access to a sorted set is possible via Index +} + + +void OResultSet::OpenImpl() +{ + OSL_ENSURE(m_pSQLAnalyzer,"No analyzer set with setSqlAnalyzer!"); + if(!m_pTable.is()) + { + const OSQLTables& rTabs = m_aSQLIterator.getTables(); + if (rTabs.empty() || !rTabs.begin()->second.is()) + lcl_throwError(STR_QUERY_TOO_COMPLEX,*this); + + if ( rTabs.size() > 1 || m_aSQLIterator.hasErrors() ) + lcl_throwError(STR_QUERY_MORE_TABLES,*this); + + OSQLTable xTable = rTabs.begin()->second; + m_xColumns = m_aSQLIterator.getSelectColumns(); + + m_xColNames = xTable->getColumns(); + m_xColsIdx.set(m_xColNames,UNO_QUERY); + doTableSpecials(xTable); + Reference<XComponent> xComp(xTable,UNO_QUERY); + if(xComp.is()) + xComp->addEventListener(this); + } + + m_pTable->refreshHeader(); + + sal_Int32 nColumnCount = m_xColsIdx->getCount(); + + initializeRow(m_aRow,nColumnCount); + initializeRow(m_aEvaluateRow,nColumnCount); + initializeRow(m_aInsertRow,nColumnCount); + + + m_nResultSetConcurrency = (m_pTable->isReadOnly() || isCount()) ? ResultSetConcurrency::READ_ONLY : ResultSetConcurrency::UPDATABLE; + + // create new Index: + m_pFileSet = nullptr; + + // position at the beginning + m_nRowPos = -1; + m_nFilePos = 0; + m_nRowCountResult = -1; + m_pTable->seekRow(IResultSetHelper::ABSOLUTE1, 0, m_nFilePos); + + m_nLastVisitedPos = m_pTable->getCurrentLastPos(); + + switch(m_aSQLIterator.getStatementType()) + { + case OSQLStatementType::Select: + { + if(isCount()) + { + if(m_xColumns->size() > 1) + lcl_throwError(STR_QUERY_COMPLEX_COUNT,*this); + + m_nRowCountResult = 0; + // for now simply iterate over all rows and + // do all actions (or just count) + { + bool bOK = true; + while (bOK) + { + bOK = ExecuteRow(IResultSetHelper::NEXT); + + if (bOK) + { + m_nRowCountResult++; + } + } + + // save result of COUNT(*) in m_nRowCountResult. + // nRowCount (number of Rows in the result) = 1 for this request! + } + } + else + { + bool bDistinct = false; + assert(m_pParseTree != nullptr); + OSQLParseNode *pDistinct = m_pParseTree->getChild(1); + + assert(m_aOrderbyColumnNumber.size() == + m_aOrderbyAscending.size()); + if (pDistinct && pDistinct->getTokenID() == SQL_TOKEN_DISTINCT ) + { + // To eliminate duplicates we need to sort on all columns. + // This is not a problem because the SQL spec says that the + // order of columns that are not specified in ORDER BY + // clause is undefined, so it doesn't hurt to sort on + // these; pad the vectors to include them. + for (size_t i = 1; // 0: bookmark (see setBoundedColumns) + i < m_aColMapping.size(); ++i) + { + if (std::find(m_aOrderbyColumnNumber.begin(), + m_aOrderbyColumnNumber.end(), + sal::static_int_cast<sal_Int32>(i)) + == m_aOrderbyColumnNumber.end()) + { + m_aOrderbyColumnNumber.push_back(i); + // ASC or DESC doesn't matter + m_aOrderbyAscending.push_back(TAscendingOrder::ASC); + } + } + bDistinct = true; + } + + if (IsSorted()) + sortRows(); + + if (!m_pFileSet.is()) + { + m_pFileSet = new OKeySet(); + + if (!m_pSQLAnalyzer->hasRestriction()) + // now the Keyset can be filled! + // But be careful: It is assumed, that the FilePositions will be stored as sequence 1..n + { + if ( m_nLastVisitedPos > 0) + m_pFileSet->reserve( m_nLastVisitedPos ); + for (sal_Int32 i = 0; i < m_nLastVisitedPos; i++) + m_pFileSet->push_back(i + 1); + } + } + OSL_ENSURE(m_pFileSet.is(),"No KeySet existing! :-("); + + if(bDistinct && m_pFileSet.is()) + { + OValueRow aSearchRow = new OValueVector(m_aRow->size()); + OValueRefVector::iterator aRowIter = m_aRow->begin(); + OValueVector::iterator aSearchIter = aSearchRow->begin(); + for ( ++aRowIter,++aSearchIter; // the first column is the bookmark column + aRowIter != m_aRow->end(); + ++aRowIter,++aSearchIter) + aSearchIter->setBound((*aRowIter)->isBound()); + + size_t nMaxRow = m_pFileSet->size(); + + if (nMaxRow) + { + #if OSL_DEBUG_LEVEL > 1 + sal_Int32 nFound=0; + #endif + sal_Int32 nPos; + sal_Int32 nKey; + + for( size_t j = nMaxRow-1; j > 0; --j) + { + nPos = (*m_pFileSet)[j]; + ExecuteRow(IResultSetHelper::BOOKMARK,nPos,false); + m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping); + { // cop*y row values + OValueRefVector::iterator copyFrom = m_aSelectRow->begin(); + OValueVector::iterator copyTo = aSearchRow->begin(); + for ( ++copyFrom,++copyTo; // the first column is the bookmark column + copyFrom != m_aSelectRow->end(); + ++copyFrom,++copyTo) + *copyTo = *(*copyFrom); + } + + // compare with next row + nKey = (*m_pFileSet)[j-1]; + ExecuteRow(IResultSetHelper::BOOKMARK,nKey,false); + m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping); + auto rowsMismatchIters = std::mismatch(std::next(m_aSelectRow->begin()), m_aSelectRow->end(), + std::next(aSearchRow->begin()), // the first column is the bookmark column + [](const OValueRefVector::value_type& a, const OValueVector::value_type& b) { + return !a->isBound() || (*a == b); }); + + if(rowsMismatchIters.first == m_aSelectRow->end()) + (*m_pFileSet)[j] = 0; // Rows match -- Mark for deletion by setting key to 0 + #if OSL_DEBUG_LEVEL > 1 + else + nFound++; + #endif + } + + m_pFileSet->erase(std::remove(m_pFileSet->begin(),m_pFileSet->end(),0) + ,m_pFileSet->end()); + } + } + } + } break; + + case OSQLStatementType::Update: + case OSQLStatementType::Delete: + // during processing count the number of processed Rows + m_nRowCountResult = 0; + // for now simply iterate over all rows and + // run the actions (or simply count): + { + + bool bOK = true; + while (bOK) + { + bOK = ExecuteRow(IResultSetHelper::NEXT); + + if (bOK) + { + m_nRowCountResult++; + } + } + + // save result of COUNT(*) in nRowCountResult. + // nRowCount (number of rows in the result-set) = 1 for this request! + } + break; + case OSQLStatementType::Insert: + m_nRowCountResult = 0; + + OSL_ENSURE(m_aAssignValues.is(),"No assign values set!"); + if(!m_pTable->InsertRow(*m_aAssignValues, m_xColsIdx)) + { + m_nFilePos = 0; + return; + } + + m_nRowCountResult = 1; + break; + default: + SAL_WARN( "connectivity.drivers", "OResultSet::OpenImpl: unsupported statement type!" ); + break; + } + + // reset FilePos + m_nFilePos = 0; +} + +Sequence< sal_Int8 > OResultSet::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OResultSet::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OResultSet>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : 0; +} + +void OResultSet::setBoundedColumns(const OValueRefRow& _rRow, + const OValueRefRow& _rSelectRow, + const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns, + const Reference<XIndexAccess>& _xNames, + bool _bSetColumnMapping, + const Reference<XDatabaseMetaData>& _xMetaData, + std::vector<sal_Int32>& _rColMapping) +{ + ::comphelper::UStringMixEqual aCase(_xMetaData->supportsMixedCaseQuotedIdentifiers()); + + Reference<XPropertySet> xTableColumn; + OUString sTableColumnName, sSelectColumnRealName; + + const OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME); + const OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME); + const OUString sType = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE); + + std::map<OSQLColumns::iterator,bool> aSelectIters; + OValueRefVector::const_iterator aRowIter = _rRow->begin()+1; + for (sal_Int32 i=0; // the first column is the bookmark column + aRowIter != _rRow->end(); + ++i, ++aRowIter + ) + { + (*aRowIter)->setBound(false); + try + { + // get the table column and its name + _xNames->getByIndex(i) >>= xTableColumn; + OSL_ENSURE(xTableColumn.is(), "OResultSet::setBoundedColumns: invalid table column!"); + if (xTableColumn.is()) + xTableColumn->getPropertyValue(sName) >>= sTableColumnName; + else + sTableColumnName.clear(); + + // look if we have such a select column + // TODO: would like to have a O(log n) search here ... + for ( OSQLColumns::iterator aIter = _rxColumns->begin(); + aIter != _rxColumns->end(); + ++aIter + ) + { + if((*aIter)->getPropertySetInfo()->hasPropertyByName(sRealName)) + (*aIter)->getPropertyValue(sRealName) >>= sSelectColumnRealName; + else + (*aIter)->getPropertyValue(sName) >>= sSelectColumnRealName; + + if ( aCase(sTableColumnName, sSelectColumnRealName) && !(*aRowIter)->isBound() && aSelectIters.end() == aSelectIters.find(aIter) ) + { + aSelectIters.emplace(aIter,true); + if(_bSetColumnMapping) + { + sal_Int32 nSelectColumnPos = aIter - _rxColumns->begin() + 1; + // the getXXX methods are 1-based ... + sal_Int32 nTableColumnPos = i + 1; + // get first table column is the bookmark column ... + _rColMapping[nSelectColumnPos] = nTableColumnPos; + (*_rSelectRow)[nSelectColumnPos] = *aRowIter; + } + + (*aRowIter)->setBound(true); + sal_Int32 nType = DataType::OTHER; + if (xTableColumn.is()) + xTableColumn->getPropertyValue(sType) >>= nType; + (*aRowIter)->setTypeKind(nType); + + break; + } + } + } + catch (Exception&) + { + SAL_WARN( "connectivity.drivers","OResultSet::setBoundedColumns: caught an Exception!"); + } + } + // in this case we got more select columns as columns exist in the table + if ( !(_bSetColumnMapping && aSelectIters.size() != _rColMapping.size()) ) + return; + + Reference<XNameAccess> xNameAccess(_xNames,UNO_QUERY); + Sequence< OUString > aSelectColumns = xNameAccess->getElementNames(); + + for ( OSQLColumns::iterator aIter = _rxColumns->begin(); + aIter != _rxColumns->end(); + ++aIter + ) + { + if ( aSelectIters.end() == aSelectIters.find(aIter) ) + { + if ( (*aIter)->getPropertySetInfo()->hasPropertyByName(sRealName) ) + (*aIter)->getPropertyValue(sRealName) >>= sSelectColumnRealName; + else + (*aIter)->getPropertyValue(sName) >>= sSelectColumnRealName; + + if ( xNameAccess->hasByName( sSelectColumnRealName ) ) + { + aSelectIters.emplace(aIter,true); + sal_Int32 nSelectColumnPos = aIter - _rxColumns->begin() + 1; + const OUString* pBegin = aSelectColumns.getConstArray(); + const OUString* pEnd = pBegin + aSelectColumns.getLength(); + for(sal_Int32 i=0;pBegin != pEnd;++pBegin,++i) + { + if ( aCase(*pBegin, sSelectColumnRealName) ) + { + // the getXXX methods are 1-based ... + sal_Int32 nTableColumnPos = i + 1; + // get first table column is the bookmark column ... + _rColMapping[nSelectColumnPos] = nTableColumnPos; + (*_rSelectRow)[nSelectColumnPos] = (*_rRow)[nTableColumnPos]; + break; + } + } + } + } + } +} + +void SAL_CALL OResultSet::acquire() throw() +{ + OResultSet_BASE::acquire(); +} + +void SAL_CALL OResultSet::release() throw() +{ + OResultSet_BASE::release(); +} + +Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +void OResultSet::doTableSpecials(const OSQLTable& _xTable) +{ + Reference<css::lang::XUnoTunnel> xTunnel(_xTable, UNO_QUERY_THROW); + m_pTable = reinterpret_cast< OFileTable* >(xTunnel->getSomething(OFileTable::getUnoTunnelId())); + assert(m_pTable.is()); +} + +void OResultSet::clearInsertRow() +{ + m_aRow->setDeleted(false); // set to false here because this is the new row + sal_Int32 nPos = 0; + for(ORowSetValueDecoratorRef& rValue : *m_aInsertRow) + { + if ( rValue->isBound() ) + { + (*m_aRow)[nPos]->setValue( rValue->getValue() ); + } + rValue->setBound(nPos == 0); + rValue->setModified(false); + rValue->setNull(); + ++nPos; + } +} + +void OResultSet::initializeRow(OValueRefRow& _rRow,sal_Int32 _nColumnCount) +{ + if(!_rRow.is()) + { + _rRow = new OValueRefVector(_nColumnCount); + (*_rRow)[0]->setBound(true); + std::for_each(_rRow->begin()+1,_rRow->end(),TSetRefBound(false)); + } +} + +bool OResultSet::fillIndexValues(const Reference< XColumnsSupplier> &/*_xIndex*/) +{ + return false; +} + +bool OResultSet::move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) +{ + return Move(_eCursorPosition,_nOffset,_bRetrieveData); +} + +sal_Int32 OResultSet::getDriverPos() const +{ + return (*m_aRow)[0]->getValue(); +} + +bool OResultSet::isRowDeleted() const +{ + return m_aRow->isDeleted(); +} + +void SAL_CALL OResultSet::disposing( const EventObject& Source ) +{ + Reference<XPropertySet> xProp = m_pTable.get(); + if(m_pTable.is() && Source.Source == xProp) + { + m_pTable.clear(); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FResultSetMetaData.cxx b/connectivity/source/drivers/file/FResultSetMetaData.cxx new file mode 100644 index 000000000..f68a06532 --- /dev/null +++ b/connectivity/source/drivers/file/FResultSetMetaData.cxx @@ -0,0 +1,187 @@ +/* -*- 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 <file/FResultSetMetaData.hxx> +#include <file/FTable.hxx> +#include <comphelper/extract.hxx> +#include <connectivity/dbexception.hxx> +#include <comphelper/types.hxx> + + +using namespace ::comphelper; +using namespace connectivity; +using namespace dbtools; +using namespace connectivity::file; +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; + + +OResultSetMetaData::OResultSetMetaData(const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,const OUString& _aTableName,OFileTable* _pTable) + :m_aTableName(_aTableName) + ,m_xColumns(_rxColumns) + ,m_pTable(_pTable) +{ +} + + +OResultSetMetaData::~OResultSetMetaData() +{ + m_xColumns = nullptr; +} + +void OResultSetMetaData::checkColumnIndex(sal_Int32 column) +{ + if(column <= 0 || column > static_cast<sal_Int32>(m_xColumns->size())) + throwInvalidIndexException(*this); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + return getPrecision(column); +} + + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 column ) +{ + checkColumnIndex(column); + return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))); +} + + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount( ) +{ + return m_xColumns->size(); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive( sal_Int32 /*column*/ ) +{ + return false; +} + + +OUString SAL_CALL OResultSetMetaData::getSchemaName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + + +OUString SAL_CALL OResultSetMetaData::getColumnName( sal_Int32 column ) +{ + checkColumnIndex(column); + + Any aName((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))); + return aName.hasValue() ? getString(aName) : getString((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))); +} + +OUString SAL_CALL OResultSetMetaData::getTableName( sal_Int32 /*column*/ ) +{ + return m_aTableName; +} + +OUString SAL_CALL OResultSetMetaData::getCatalogName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +OUString SAL_CALL OResultSetMetaData::getColumnTypeName( sal_Int32 column ) +{ + checkColumnIndex(column); + return getString((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))); +} + +OUString SAL_CALL OResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + return getColumnName(column); +} + +OUString SAL_CALL OResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isCurrency( sal_Int32 column ) +{ + checkColumnIndex(column); + return getBOOL((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement( sal_Int32 /*setCatalogcolumn*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 /*column*/ ) +{ + return true; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column ) +{ + checkColumnIndex(column); + return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column ) +{ + checkColumnIndex(column); + return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))); +} + + +sal_Int32 SAL_CALL OResultSetMetaData::isNullable( sal_Int32 column ) +{ + checkColumnIndex(column); + return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isSearchable( sal_Int32 /*column*/ ) +{ + return true; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isReadOnly( sal_Int32 column ) +{ + checkColumnIndex(column); + return m_pTable->isReadOnly() || ( + (*m_xColumns)[column-1]->getPropertySetInfo()->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION)) && + ::cppu::any2bool((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION)))); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + return !isReadOnly(column); +} + +sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 column ) +{ + return !isReadOnly(column); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FStatement.cxx b/connectivity/source/drivers/file/FStatement.cxx new file mode 100644 index 000000000..08c4f7fdd --- /dev/null +++ b/connectivity/source/drivers/file/FStatement.cxx @@ -0,0 +1,710 @@ +/* -*- 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 <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <file/FStatement.hxx> +#include <file/FConnection.hxx> +#include <sqlbison.hxx> +#include <file/FDriver.hxx> +#include <file/FResultSet.hxx> +#include <sal/log.hxx> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <comphelper/sequence.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> +#include <algorithm> + +namespace connectivity::file +{ + + +using namespace dbtools; +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::sdbcx; +using namespace com::sun::star::container; + +OStatement_Base::OStatement_Base(OConnection* _pConnection ) + :OStatement_BASE(m_aMutex) + ,::comphelper::OPropertyContainer(OStatement_BASE::rBHelper) + ,m_xDBMetaData(_pConnection->getMetaData()) + ,m_aParser( _pConnection->getDriver()->getComponentContext() ) + ,m_aSQLIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser ) + ,m_pConnection(_pConnection) + ,m_pParseTree(nullptr) + ,m_nMaxFieldSize(0) + ,m_nMaxRows(0) + ,m_nQueryTimeOut(0) + ,m_nFetchSize(0) + ,m_nResultSetType(ResultSetType::FORWARD_ONLY) + ,m_nFetchDirection(FetchDirection::FORWARD) + ,m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE) + ,m_bEscapeProcessing(true) +{ + sal_Int32 nAttrib = 0; + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), PROPERTY_ID_CURSORNAME, nAttrib,&m_aCursorName, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), PROPERTY_ID_MAXFIELDSIZE, nAttrib,&m_nMaxFieldSize, ::cppu::UnoType<sal_Int32>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), PROPERTY_ID_MAXROWS, nAttrib,&m_nMaxRows, ::cppu::UnoType<sal_Int32>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), PROPERTY_ID_QUERYTIMEOUT, nAttrib,&m_nQueryTimeOut, ::cppu::UnoType<sal_Int32>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, nAttrib,&m_nFetchSize, ::cppu::UnoType<sal_Int32>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, nAttrib,&m_nResultSetType, ::cppu::UnoType<sal_Int32>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, nAttrib,&m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),PROPERTY_ID_ESCAPEPROCESSING, nAttrib,&m_bEscapeProcessing,cppu::UnoType<bool>::get()); + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY, nAttrib,&m_nResultSetConcurrency, ::cppu::UnoType<sal_Int32>::get()); +} + +OStatement_Base::~OStatement_Base() +{ + osl_atomic_increment( &m_refCount ); + disposing(); +} + +void OStatement_Base::disposeResultSet() +{ + SAL_INFO( "connectivity.drivers", "file Ocke.Janssen@sun.com OStatement_Base::disposeResultSet" ); + // free the cursor if alive + Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY); + assert(xComp.is() || !m_xResultSet.get().is()); + if (xComp.is()) + xComp->dispose(); + m_xResultSet.clear(); +} + +void OStatement_BASE2::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + disposeResultSet(); + + if(m_pSQLAnalyzer) + m_pSQLAnalyzer->dispose(); + + if(m_aRow.is()) + { + m_aRow->clear(); + m_aRow = nullptr; + } + + m_aSQLIterator.dispose(); + + m_pTable.clear(); + + m_pConnection.clear(); + + if ( m_pParseTree ) + { + delete m_pParseTree; + m_pParseTree = nullptr; + } + + OStatement_Base::disposing(); +} + +void SAL_CALL OStatement_Base::acquire() throw() +{ + OStatement_BASE::acquire(); +} + +void SAL_CALL OStatement_BASE2::release() throw() +{ + OStatement_BASE::release(); +} + +Any SAL_CALL OStatement_Base::queryInterface( const Type & rType ) +{ + const Any aRet = OStatement_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OStatement_Base::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(),OStatement_BASE::getTypes()); +} + + +void SAL_CALL OStatement_Base::cancel( ) +{ +} + +void SAL_CALL OStatement_Base::close() +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + } + dispose(); +} + +void OStatement_Base::closeResultSet() +{ + SAL_INFO( "connectivity.drivers", "file Ocke.Janssen@sun.com OStatement_Base::clearMyResultSet " ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + Reference< XCloseable > xCloseable(m_xResultSet.get(), UNO_QUERY); + assert(xCloseable.is() || !m_xResultSet.get().is()); + if (xCloseable.is()) + { + try + { + xCloseable->close(); + } + catch( const DisposedException& ) { } + } + + m_xResultSet.clear(); +} + +Any SAL_CALL OStatement_Base::getWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + return makeAny(m_aLastWarning); +} + +void SAL_CALL OStatement_Base::clearWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + m_aLastWarning = SQLWarning(); +} + +::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + + +::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper() +{ + return *getArrayHelper(); +} + +OResultSet* OStatement::createResultSet() +{ + return new OResultSet(this,m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbc.driver.file.Statement","com.sun.star.sdbc.Statement"); + +void SAL_CALL OStatement::acquire() throw() +{ + OStatement_BASE2::acquire(); +} + +void SAL_CALL OStatement::release() throw() +{ + OStatement_BASE2::release(); +} + + +sal_Bool SAL_CALL OStatement::execute( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + executeQuery(sql); + + return m_aSQLIterator.getStatementType() == OSQLStatementType::Select; +} + + +Reference< XResultSet > SAL_CALL OStatement::executeQuery( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + construct(sql); + Reference< XResultSet > xRS; + OResultSet* pResult = createResultSet(); + xRS = pResult; + initializeResultSet(pResult); + m_xResultSet = xRS; + + pResult->OpenImpl(); + + return xRS; +} + +Reference< XConnection > SAL_CALL OStatement::getConnection( ) +{ + return Reference< XConnection >(m_pConnection.get()); +} + +sal_Int32 SAL_CALL OStatement::executeUpdate( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + construct(sql); + rtl::Reference<OResultSet> pResult = createResultSet(); + initializeResultSet(pResult.get()); + pResult->OpenImpl(); + + return pResult->getRowCountResult(); +} + + +void SAL_CALL OStatement_Base::disposing() +{ + if(m_aEvaluateRow.is()) + { + m_aEvaluateRow->clear(); + m_aEvaluateRow = nullptr; + } + OStatement_BASE::disposing(); +} + +Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +Any SAL_CALL OStatement::queryInterface( const Type & rType ) +{ + Any aRet = OStatement_XStatement::queryInterface( rType); + return aRet.hasValue() ? aRet : OStatement_BASE2::queryInterface( rType); +} + +void OStatement_Base::anylizeSQL() +{ + OSL_ENSURE(m_pSQLAnalyzer,"OResultSet::anylizeSQL: Analyzer isn't set!"); + // start analysing the statement + m_pSQLAnalyzer->setOrigColumns(m_xColNames); + m_pSQLAnalyzer->start(m_pParseTree); + + const OSQLParseNode* pOrderbyClause = m_aSQLIterator.getOrderTree(); + if(!pOrderbyClause) + return; + + OSQLParseNode * pOrderingSpecCommalist = pOrderbyClause->getChild(2); + OSL_ENSURE(SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OResultSet: Error in Parse Tree"); + + for (size_t m = 0; m < pOrderingSpecCommalist->count(); m++) + { + OSQLParseNode * pOrderingSpec = pOrderingSpecCommalist->getChild(m); + OSL_ENSURE(SQL_ISRULE(pOrderingSpec,ordering_spec),"OResultSet: Error in Parse Tree"); + OSL_ENSURE(pOrderingSpec->count() == 2,"OResultSet: Error in Parse Tree"); + + OSQLParseNode * pColumnRef = pOrderingSpec->getChild(0); + if(!SQL_ISRULE(pColumnRef,column_ref)) + { + throw SQLException(); + } + OSQLParseNode * pAscendingDescending = pOrderingSpec->getChild(1); + setOrderbyColumn(pColumnRef,pAscendingDescending); + } +} + +void OStatement_Base::setOrderbyColumn( OSQLParseNode const * pColumnRef, + OSQLParseNode const * pAscendingDescending) +{ + OUString aColumnName; + if (pColumnRef->count() == 1) + aColumnName = pColumnRef->getChild(0)->getTokenValue(); + else if (pColumnRef->count() == 3) + { + pColumnRef->getChild(2)->parseNodeToStr( aColumnName, getOwnConnection(), nullptr, false, false ); + } + else + { + throw SQLException(); + } + + Reference<XColumnLocate> xColLocate(m_xColNames,UNO_QUERY); + if(!xColLocate.is()) + return; + // Everything tested and we have the name of the Column. + // What number is the Column? + ::rtl::Reference<OSQLColumns> aSelectColumns = m_aSQLIterator.getSelectColumns(); + ::comphelper::UStringMixEqual aCase; + OSQLColumns::const_iterator aFind = ::connectivity::find(aSelectColumns->begin(),aSelectColumns->end(),aColumnName,aCase); + if ( aFind == aSelectColumns->end() ) + throw SQLException(); + m_aOrderbyColumnNumber.push_back((aFind - aSelectColumns->begin()) + 1); + + // Ascending or Descending? + m_aOrderbyAscending.push_back(SQL_ISTOKEN(pAscendingDescending,DESC) ? TAscendingOrder::DESC : TAscendingOrder::ASC); +} + +void OStatement_Base::construct(const OUString& sql) +{ + OUString aErr; + m_pParseTree = m_aParser.parseTree(aErr,sql).release(); + if(!m_pParseTree) + throw SQLException(aErr,*this,OUString(),0,Any()); + + m_aSQLIterator.setParseTree(m_pParseTree); + m_aSQLIterator.traverseAll(); + const OSQLTables& rTabs = m_aSQLIterator.getTables(); + + // sanity checks + if ( rTabs.empty() ) + // no tables -> nothing to operate on -> error + m_pConnection->throwGenericSQLException(STR_QUERY_NO_TABLE,*this); + + if ( rTabs.size() > 1 || m_aSQLIterator.hasErrors() ) + // more than one table -> can't operate on them -> error + m_pConnection->throwGenericSQLException(STR_QUERY_MORE_TABLES,*this); + + if ( (m_aSQLIterator.getStatementType() == OSQLStatementType::Select) && m_aSQLIterator.getSelectColumns()->empty() ) + // SELECT statement without columns -> error + m_pConnection->throwGenericSQLException(STR_QUERY_NO_COLUMN,*this); + + switch(m_aSQLIterator.getStatementType()) + { + case OSQLStatementType::CreateTable: + case OSQLStatementType::OdbcCall: + case OSQLStatementType::Unknown: + m_pConnection->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,*this); + break; + default: + break; + } + + // at this moment we support only one table per select statement + Reference< css::lang::XUnoTunnel> xTunnel(rTabs.begin()->second,UNO_QUERY); + if(xTunnel.is()) + { + m_pTable = reinterpret_cast<OFileTable*>(xTunnel->getSomething(OFileTable::getUnoTunnelId())); + } + OSL_ENSURE(m_pTable.is(),"No table!"); + if ( m_pTable.is() ) + m_xColNames = m_pTable->getColumns(); + Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY); + // set the binding of the resultrow + m_aRow = new OValueRefVector(xNames->getCount()); + (*m_aRow)[0]->setBound(true); + std::for_each(m_aRow->begin()+1,m_aRow->end(),TSetRefBound(false)); + + // set the binding of the resultrow + m_aEvaluateRow = new OValueRefVector(xNames->getCount()); + + (*m_aEvaluateRow)[0]->setBound(true); + std::for_each(m_aEvaluateRow->begin()+1,m_aEvaluateRow->end(),TSetRefBound(false)); + + // set the select row + m_aSelectRow = new OValueRefVector(m_aSQLIterator.getSelectColumns()->size()); + std::for_each(m_aSelectRow->begin(),m_aSelectRow->end(),TSetRefBound(true)); + + // create the column mapping + createColumnMapping(); + + m_pSQLAnalyzer.reset( new OSQLAnalyzer(m_pConnection.get()) ); + + anylizeSQL(); +} + +void OStatement_Base::createColumnMapping() +{ + // initialize the column index map (mapping select columns to table columns) + ::rtl::Reference<connectivity::OSQLColumns> xColumns = m_aSQLIterator.getSelectColumns(); + m_aColMapping.resize(xColumns->size() + 1); + for (sal_Int32 i=0; i<static_cast<sal_Int32>(m_aColMapping.size()); ++i) + m_aColMapping[i] = i; + + Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY); + // now check which columns are bound + OResultSet::setBoundedColumns(m_aRow,m_aSelectRow,xColumns,xNames,true,m_xDBMetaData,m_aColMapping); +} + +void OStatement_Base::initializeResultSet(OResultSet* _pResult) +{ + GetAssignValues(); + + _pResult->setSqlAnalyzer(m_pSQLAnalyzer.get()); + _pResult->setOrderByColumns(m_aOrderbyColumnNumber); + _pResult->setOrderByAscending(m_aOrderbyAscending); + _pResult->setBindingRow(m_aRow); + _pResult->setColumnMapping(m_aColMapping); + _pResult->setEvaluationRow(m_aEvaluateRow); + _pResult->setAssignValues(m_aAssignValues); + _pResult->setSelectRow(m_aSelectRow); + + m_pSQLAnalyzer->bindSelectRow(m_aRow); + m_pSQLAnalyzer->bindEvaluationRow(m_aEvaluateRow); // Set values in the code of the Compiler +} + +void OStatement_Base::GetAssignValues() +{ + if (m_pParseTree == nullptr) + { + ::dbtools::throwFunctionSequenceException(*this); + return; + } + + if (SQL_ISRULE(m_pParseTree,select_statement)) + // no values have to be set for SELECT + return; + else if (SQL_ISRULE(m_pParseTree,insert_statement)) + { + // Create Row for the values to be set (Reference through new) + if(m_aAssignValues.is()) + m_aAssignValues->clear(); + sal_Int32 nCount = Reference<XIndexAccess>(m_xColNames,UNO_QUERY_THROW)->getCount(); + m_aAssignValues = new OAssignValues(nCount); + // unbound all + std::for_each(m_aAssignValues->begin()+1,m_aAssignValues->end(),TSetRefBound(false)); + + m_aParameterIndexes.resize(nCount+1,SQL_NO_PARAMETER); + + // List of Column-Names, that exist in the column_commalist (separated by ;): + std::vector<OUString> aColumnNameList; + + OSL_ENSURE(m_pParseTree->count() >= 4,"OResultSet: Error in Parse Tree"); + + OSQLParseNode * pOptColumnCommalist = m_pParseTree->getChild(3); + OSL_ENSURE(pOptColumnCommalist != nullptr,"OResultSet: Error in Parse Tree"); + OSL_ENSURE(SQL_ISRULE(pOptColumnCommalist,opt_column_commalist),"OResultSet: Error in Parse Tree"); + if (pOptColumnCommalist->count() == 0) + { + const Sequence< OUString>& aNames = m_xColNames->getElementNames(); + const OUString* pBegin = aNames.getConstArray(); + const OUString* pEnd = pBegin + aNames.getLength(); + for (; pBegin != pEnd; ++pBegin) + aColumnNameList.push_back(*pBegin); + } + else + { + OSL_ENSURE(pOptColumnCommalist->count() == 3,"OResultSet: Error in Parse Tree"); + + OSQLParseNode * pColumnCommalist = pOptColumnCommalist->getChild(1); + OSL_ENSURE(pColumnCommalist != nullptr,"OResultSet: Error in Parse Tree"); + OSL_ENSURE(SQL_ISRULE(pColumnCommalist,column_commalist),"OResultSet: Error in Parse Tree"); + OSL_ENSURE(pColumnCommalist->count() > 0,"OResultSet: Error in Parse Tree"); + + // All Columns in the column_commalist ... + for (size_t i = 0; i < pColumnCommalist->count(); i++) + { + OSQLParseNode * pCol = pColumnCommalist->getChild(i); + OSL_ENSURE(pCol != nullptr,"OResultSet: Error in Parse Tree"); + aColumnNameList.push_back(pCol->getTokenValue()); + } + } + if ( aColumnNameList.empty() ) + throwFunctionSequenceException(*this); + + // Values ... + OSQLParseNode * pValuesOrQuerySpec = m_pParseTree->getChild(4); + OSL_ENSURE(pValuesOrQuerySpec != nullptr,"OResultSet: pValuesOrQuerySpec must not be NULL!"); + OSL_ENSURE(SQL_ISRULE(pValuesOrQuerySpec,values_or_query_spec),"OResultSet: ! SQL_ISRULE(pValuesOrQuerySpec,values_or_query_spec)"); + OSL_ENSURE(pValuesOrQuerySpec->count() > 0,"OResultSet: pValuesOrQuerySpec->count() <= 0"); + + // just "VALUES" is allowed ... + if (! SQL_ISTOKEN(pValuesOrQuerySpec->getChild(0),VALUES)) + throwFunctionSequenceException(*this); + + OSL_ENSURE(pValuesOrQuerySpec->count() == 4,"OResultSet: pValuesOrQuerySpec->count() != 4"); + + // List of values + OSQLParseNode * pInsertAtomCommalist = pValuesOrQuerySpec->getChild(2); + OSL_ENSURE(pInsertAtomCommalist != nullptr,"OResultSet: pInsertAtomCommalist must not be NULL!"); + OSL_ENSURE(pInsertAtomCommalist->count() > 0,"OResultSet: pInsertAtomCommalist <= 0"); + + sal_Int32 nIndex=0; + for (size_t i = 0; i < pInsertAtomCommalist->count(); i++) + { + OSQLParseNode * pRow_Value_Const = pInsertAtomCommalist->getChild(i); // row_value_constructor + OSL_ENSURE(pRow_Value_Const != nullptr,"OResultSet: pRow_Value_Const must not be NULL!"); + if(SQL_ISRULE(pRow_Value_Const,parameter)) + { + ParseAssignValues(aColumnNameList,pRow_Value_Const,nIndex++); // only one Columnname allowed per loop + } + else if(pRow_Value_Const->isToken()) + ParseAssignValues(aColumnNameList,pRow_Value_Const,i); + else + { + if(pRow_Value_Const->count() == aColumnNameList.size()) + { + for (size_t j = 0; j < pRow_Value_Const->count(); ++j) + ParseAssignValues(aColumnNameList,pRow_Value_Const->getChild(j),nIndex++); + } + else + throwFunctionSequenceException(*this); + } + } + } + else if (SQL_ISRULE(m_pParseTree,update_statement_searched)) + { + if(m_aAssignValues.is()) + m_aAssignValues->clear(); + sal_Int32 nCount = Reference<XIndexAccess>(m_xColNames,UNO_QUERY_THROW)->getCount(); + m_aAssignValues = new OAssignValues(nCount); + // unbound all + std::for_each(m_aAssignValues->begin()+1,m_aAssignValues->end(),TSetRefBound(false)); + + m_aParameterIndexes.resize(nCount+1,SQL_NO_PARAMETER); + + OSL_ENSURE(m_pParseTree->count() >= 4,"OResultSet: Error in Parse Tree"); + + OSQLParseNode * pAssignmentCommalist = m_pParseTree->getChild(3); + OSL_ENSURE(pAssignmentCommalist != nullptr,"OResultSet: pAssignmentCommalist == NULL"); + OSL_ENSURE(SQL_ISRULE(pAssignmentCommalist,assignment_commalist),"OResultSet: Error in Parse Tree"); + OSL_ENSURE(pAssignmentCommalist->count() > 0,"OResultSet: pAssignmentCommalist->count() <= 0"); + + // work on all assignments (commalist) ... + std::vector< OUString> aList(1); + for (size_t i = 0; i < pAssignmentCommalist->count(); i++) + { + OSQLParseNode * pAssignment = pAssignmentCommalist->getChild(i); + OSL_ENSURE(pAssignment != nullptr,"OResultSet: pAssignment == NULL"); + OSL_ENSURE(SQL_ISRULE(pAssignment,assignment),"OResultSet: Error in Parse Tree"); + OSL_ENSURE(pAssignment->count() == 3,"OResultSet: pAssignment->count() != 3"); + + OSQLParseNode * pCol = pAssignment->getChild(0); + OSL_ENSURE(pCol != nullptr,"OResultSet: pCol == NULL"); + + OSQLParseNode * pComp = pAssignment->getChild(1); + OSL_ENSURE(pComp != nullptr,"OResultSet: pComp == NULL"); + OSL_ENSURE(pComp->getNodeType() == SQLNodeType::Equal,"OResultSet: pComp->getNodeType() != SQLNodeType::Comparison"); + if (pComp->getTokenValue().toChar() != '=') + { + throwFunctionSequenceException(*this); + } + + OSQLParseNode * pVal = pAssignment->getChild(2); + OSL_ENSURE(pVal != nullptr,"OResultSet: pVal == NULL"); + aList[0] = pCol->getTokenValue(); + ParseAssignValues(aList,pVal,0); + } + + } +} + +void OStatement_Base::ParseAssignValues(const std::vector< OUString>& aColumnNameList,OSQLParseNode* pRow_Value_Constructor_Elem, sal_Int32 nIndex) +{ + OSL_ENSURE(o3tl::make_unsigned(nIndex) <= aColumnNameList.size(),"SdbFileCursor::ParseAssignValues: nIndex > aColumnNameList.GetTokenCount()"); + OUString aColumnName(aColumnNameList[nIndex]); + OSL_ENSURE(aColumnName.getLength() > 0,"OResultSet: Column-Name not found"); + OSL_ENSURE(pRow_Value_Constructor_Elem != nullptr,"OResultSet: pRow_Value_Constructor_Elem must not be NULL!"); + + if (pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::String || + pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::IntNum || + pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::ApproxNum) + { + // set value: + SetAssignValue(aColumnName, pRow_Value_Constructor_Elem->getTokenValue()); + } + else if (SQL_ISTOKEN(pRow_Value_Constructor_Elem,NULL)) + { + // set NULL + SetAssignValue(aColumnName, OUString(), true); + } + else if (SQL_ISRULE(pRow_Value_Constructor_Elem,parameter)) + parseParamterElem(aColumnName,pRow_Value_Constructor_Elem); + else + { + throwFunctionSequenceException(*this); + } +} + +void OStatement_Base::SetAssignValue(const OUString& aColumnName, + const OUString& aValue, + bool bSetNull, + sal_uInt32 nParameter) +{ + Reference<XPropertySet> xCol; + m_xColNames->getByName(aColumnName) >>= xCol; + sal_Int32 nId = Reference<XColumnLocate>(m_xColNames,UNO_QUERY_THROW)->findColumn(aColumnName); + // does this column actually exist in the file? + + if (!xCol.is()) + { + // This Column doesn't exist! + throwFunctionSequenceException(*this); + } + + + // Everything tested and we have the names of the Column. + // Now allocate one Value, set the value and tie the value to the Row. + if (bSetNull) + (*m_aAssignValues)[nId]->setNull(); + else + { + switch (::comphelper::getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))) + { + // put criteria depending on the Type as String or double in the variable + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + *(*m_aAssignValues)[nId] = ORowSetValue(aValue); + //Characterset is already converted, since the entire statement was converted + break; + + case DataType::BIT: + if (aValue.equalsIgnoreAsciiCase("TRUE") || aValue[0] == '1') + *(*m_aAssignValues)[nId] = true; + else if (aValue.equalsIgnoreAsciiCase("FALSE") || aValue[0] == '0') + *(*m_aAssignValues)[nId] = false; + else + throwFunctionSequenceException(*this); + break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + *(*m_aAssignValues)[nId] = ORowSetValue(aValue); + break; + default: + throwFunctionSequenceException(*this); + } + } + + // save Parameter-No. (as User Data) + // SQL_NO_PARAMETER = no Parameter. + m_aAssignValues->setParameterIndex(nId,nParameter); + if(nParameter != SQL_NO_PARAMETER) + m_aParameterIndexes[nParameter] = nId; +} + +void OStatement_Base::parseParamterElem(const OUString& /*_sColumnName*/,OSQLParseNode* /*pRow_Value_Constructor_Elem*/) +{ + // do nothing here +} + +}// namespace + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FStringFunctions.cxx b/connectivity/source/drivers/file/FStringFunctions.cxx new file mode 100644 index 000000000..32f590e31 --- /dev/null +++ b/connectivity/source/drivers/file/FStringFunctions.cxx @@ -0,0 +1,233 @@ +/* -*- 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 <file/FStringFunctions.hxx> +#include <rtl/ustrbuf.hxx> + +using namespace connectivity; +using namespace connectivity::file; + +ORowSetValue OOp_Upper::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return lhs.getString().toAsciiUpperCase(); +} + +ORowSetValue OOp_Lower::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return lhs.getString().toAsciiLowerCase(); +} + +ORowSetValue OOp_Ascii::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + OString sStr(OUStringToOString(lhs,RTL_TEXTENCODING_ASCII_US)); + sal_Int32 nAscii = sStr.toChar(); + return nAscii; +} + +ORowSetValue OOp_CharLength::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + return lhs.getString().getLength(); +} + +ORowSetValue OOp_Char::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( lhs.empty() ) + return ORowSetValue(); + + OUStringBuffer sRet; + std::vector<ORowSetValue>::const_reverse_iterator aIter = lhs.rbegin(); + std::vector<ORowSetValue>::const_reverse_iterator aEnd = lhs.rend(); + for (; aIter != aEnd; ++aIter) + { + if ( !aIter->isNull() ) + { + char c = static_cast<char>(static_cast<sal_Int32>(*aIter)); + + sRet.appendAscii(&c, 1); + } + } + + return sRet.makeStringAndClear(); +} + +ORowSetValue OOp_Concat::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( lhs.empty() ) + return ORowSetValue(); + + OUStringBuffer sRet; + std::vector<ORowSetValue>::const_reverse_iterator aIter = lhs.rbegin(); + std::vector<ORowSetValue>::const_reverse_iterator aEnd = lhs.rend(); + for (; aIter != aEnd; ++aIter) + { + if ( aIter->isNull() ) + return ORowSetValue(); + + sRet.append(aIter->operator OUString()); + } + + return sRet.makeStringAndClear(); +} + +ORowSetValue OOp_Locate::operate(const std::vector<ORowSetValue>& lhs) const +{ + if (std::any_of(lhs.begin(), lhs.end(), [](const ORowSetValue& rValue) { return rValue.isNull(); })) + return ORowSetValue(); + + if ( lhs.size() == 2 ) + return OUString(OUString::number(lhs[0].getString().indexOf(lhs[1].getString())+1)); + + else if ( lhs.size() != 3 ) + return ORowSetValue(); + + return lhs[1].getString().indexOf(lhs[2].getString(),lhs[0]) + 1; +} + +ORowSetValue OOp_SubString::operate(const std::vector<ORowSetValue>& lhs) const +{ + if (std::any_of(lhs.begin(), lhs.end(), [](const ORowSetValue& rValue) { return rValue.isNull(); })) + return ORowSetValue(); + + if ( lhs.size() == 2 && static_cast<sal_Int32>(lhs[0]) >= sal_Int32(0) ) + return lhs[1].getString().copy(static_cast<sal_Int32>(lhs[0])-1); + + else if ( lhs.size() != 3 || static_cast<sal_Int32>(lhs[1]) < sal_Int32(0)) + return ORowSetValue(); + + return lhs[2].getString().copy(static_cast<sal_Int32>(lhs[1])-1,lhs[0]); +} + +ORowSetValue OOp_LTrim::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + OUString sRet = lhs; + OUString sNew = sRet.trim(); + return sRet.copy(sRet.indexOf(sNew)); +} + +ORowSetValue OOp_RTrim::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + OUString sRet = lhs; + OUString sNew = sRet.trim(); + return sRet.copy(0,sRet.lastIndexOf(sNew[sNew.getLength()-1])+1); +} + +ORowSetValue OOp_Space::operate(const ORowSetValue& lhs) const +{ + if ( lhs.isNull() ) + return lhs; + + const char c = ' '; + OUStringBuffer sRet; + sal_Int32 nCount = lhs; + for (sal_Int32 i=0; i < nCount; ++i) + { + sRet.appendAscii(&c,1); + } + return sRet.makeStringAndClear(); +} + +ORowSetValue OOp_Replace::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( lhs.size() != 3 ) + return ORowSetValue(); + + OUString sStr = lhs[2]; + OUString sFrom = lhs[1]; + OUString sTo = lhs[0]; + sal_Int32 nIndexOf = sStr.indexOf(sFrom); + while( nIndexOf != -1 ) + { + sStr = sStr.replaceAt(nIndexOf,sFrom.getLength(),sTo); + nIndexOf = sStr.indexOf(sFrom,nIndexOf + sTo.getLength()); + } + + return sStr; +} + +ORowSetValue OOp_Repeat::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const +{ + if ( lhs.isNull() || rhs.isNull() ) + return lhs; + + OUStringBuffer sRet; + sal_Int32 nCount = rhs; + for (sal_Int32 i=0; i < nCount; ++i) + { + sRet.append(lhs.operator OUString()); + } + return sRet.makeStringAndClear(); +} + +ORowSetValue OOp_Insert::operate(const std::vector<ORowSetValue>& lhs) const +{ + if ( lhs.size() != 4 ) + return ORowSetValue(); + + OUString sStr = lhs[3]; + + sal_Int32 nStart = static_cast<sal_Int32>(lhs[2]); + if ( nStart < 1 ) + nStart = 1; + return sStr.replaceAt(nStart-1,static_cast<sal_Int32>(lhs[1]),lhs[0]); +} + +ORowSetValue OOp_Left::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const +{ + if ( lhs.isNull() || rhs.isNull() ) + return lhs; + + OUString sRet = lhs; + sal_Int32 nCount = rhs; + if ( nCount < 0 ) + return ORowSetValue(); + return sRet.copy(0,nCount); +} + +ORowSetValue OOp_Right::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const +{ + if ( lhs.isNull() || rhs.isNull() ) + return lhs; + + sal_Int32 nCount = rhs; + OUString sRet = lhs; + if ( nCount < 0 || nCount >= sRet.getLength() ) + return ORowSetValue(); + + return sRet.copy(sRet.getLength()-nCount,nCount); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FTable.cxx b/connectivity/source/drivers/file/FTable.cxx new file mode 100644 index 000000000..b47bfb811 --- /dev/null +++ b/connectivity/source/drivers/file/FTable.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 <file/FTable.hxx> +#include <file/FColumns.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <unotools/ucbstreamhelper.hxx> + +using namespace connectivity; +using namespace connectivity::file; +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; + +OFileTable::OFileTable(sdbcx::OCollection* _pTables,OConnection* _pConnection) +: OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) + ,m_pConnection(_pConnection) + ,m_nFilePos(0) + ,m_nBufferSize(0) + ,m_bWriteable(false) +{ + construct(); + m_aColumns = new OSQLColumns(); +} + +OFileTable::OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName ) + : OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers(), + Name, + Type, + Description, + SchemaName, + CatalogName) + , m_pConnection(_pConnection) + , m_nFilePos(0) + , m_nBufferSize(0) + , m_bWriteable(false) +{ + m_aColumns = new OSQLColumns(); + construct(); + // refreshColumns(); +} + +OFileTable::~OFileTable( ) +{ +} + +void OFileTable::refreshColumns() +{ + ::std::vector< OUString> aVector; + Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns(Any(), + m_SchemaName,m_Name, "%"); + + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while(xResult->next()) + aVector.push_back(xRow->getString(4)); + } + + if(m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns = new OColumns(this,m_aMutex,aVector); +} + +void OFileTable::refreshKeys() +{ +} + +void OFileTable::refreshIndexes() +{ +} + +Any SAL_CALL OFileTable::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType<XKeysSupplier>::get()|| + rType == cppu::UnoType<XRename>::get()|| + rType == cppu::UnoType<XAlterTable>::get()|| + rType == cppu::UnoType<XIndexesSupplier>::get()|| + rType == cppu::UnoType<XDataDescriptorFactory>::get()) + return Any(); + + return OTable_TYPEDEF::queryInterface(rType); +} + +void SAL_CALL OFileTable::disposing() +{ + OTable::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + + FileClose(); +} + +Sequence< sal_Int8 > OFileTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId s_Id; + + return s_Id.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OFileTable::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return isUnoTunnelId<OFileTable>(rId) + ? reinterpret_cast< sal_Int64 >( this ) + : OTable_TYPEDEF::getSomething(rId); +} + +void OFileTable::FileClose() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + if (m_pFileStream && m_pFileStream->IsWritable()) + m_pFileStream->Flush(); + + m_pFileStream.reset(); + m_pBuffer.reset(); +} + +bool OFileTable::InsertRow(OValueRefVector& /*rRow*/, const css::uno::Reference< css::container::XIndexAccess>& /*_xCols*/) +{ + return false; +} + +bool OFileTable::DeleteRow(const OSQLColumns& /*_rCols*/) +{ + return false; +} + +bool OFileTable::UpdateRow(OValueRefVector& /*rRow*/, OValueRefRow& /*pOrgRow*/,const css::uno::Reference< css::container::XIndexAccess>& /*_xCols*/) +{ + return false; +} + +void OFileTable::addColumn(const css::uno::Reference< css::beans::XPropertySet>& /*descriptor*/) +{ + OSL_FAIL( "OFileTable::addColumn: not implemented!" ); +} + +void OFileTable::dropColumn(sal_Int32 /*_nPos*/) +{ + OSL_FAIL( "OFileTable::addColumn: not implemented!" ); +} + + +std::unique_ptr<SvStream> OFileTable::createStream_simpleError( const OUString& _rFileName, StreamMode _eOpenMode) +{ + std::unique_ptr<SvStream> pReturn(::utl::UcbStreamHelper::CreateStream( _rFileName, _eOpenMode, bool(_eOpenMode & StreamMode::NOCREATE))); + if (pReturn && (ERRCODE_NONE != pReturn->GetErrorCode())) + { + pReturn.reset(); + } + return pReturn; +} + + +void OFileTable::refreshHeader() +{ +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/FTables.cxx b/connectivity/source/drivers/file/FTables.cxx new file mode 100644 index 000000000..c063f4a89 --- /dev/null +++ b/connectivity/source/drivers/file/FTables.cxx @@ -0,0 +1,54 @@ +/* -*- 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 <file/FTables.hxx> +#include <file/FCatalog.hxx> + +using namespace connectivity; +using namespace connectivity::file; +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; + +sdbcx::ObjectType OTables::createObject(const OUString& /*_rName*/) +{ + return sdbcx::ObjectType(); +} + +void OTables::impl_refresh( ) +{ + static_cast<OFileCatalog&>(m_rParent).refreshTables(); +} + +Any SAL_CALL OTables::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType<XColumnLocate>::get()|| + rType == cppu::UnoType<XDataDescriptorFactory>::get()|| + rType == cppu::UnoType<XAppend>::get()|| + rType == cppu::UnoType<XDrop>::get()) + return Any(); + + typedef sdbcx::OCollection OTables_BASE; + return OTables_BASE::queryInterface(rType); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/fanalyzer.cxx b/connectivity/source/drivers/file/fanalyzer.cxx new file mode 100644 index 000000000..a0d1305f6 --- /dev/null +++ b/connectivity/source/drivers/file/fanalyzer.cxx @@ -0,0 +1,207 @@ +/* -*- 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 <file/fanalyzer.hxx> +#include <connectivity/sqlparse.hxx> +#include <tools/debug.hxx> +#include <connectivity/sqlnode.hxx> +#include <file/FConnection.hxx> +#include <strings.hrc> + +using namespace ::connectivity; +using namespace ::connectivity::file; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; + +OSQLAnalyzer::OSQLAnalyzer(OConnection* _pConnection) + :m_pConnection(_pConnection) + ,m_bHasSelectionCode(false) + ,m_bSelectionFirstTime(true) +{ + m_aCompiler = new OPredicateCompiler(this); + m_aInterpreter = new OPredicateInterpreter(m_aCompiler); +} + + +OSQLAnalyzer::~OSQLAnalyzer() +{ +} + + +void OSQLAnalyzer::start(OSQLParseNode const * pSQLParseNode) +{ + if (SQL_ISRULE(pSQLParseNode,select_statement)) + { + DBG_ASSERT(pSQLParseNode->count() >= 4,"OFILECursor: Error in Parse Tree"); + + // check that we don't use anything other than count(*) as function + OSQLParseNode* pSelection = pSQLParseNode->getChild(2); + if ( SQL_ISRULE(pSelection,scalar_exp_commalist) ) + { + for (size_t i = 0; i < pSelection->count(); i++) + { + OSQLParseNode *pColumnRef = pSelection->getChild(i)->getChild(0); + if ( ( SQL_ISRULE(pColumnRef,set_fct_spec) && pColumnRef->count() == 4 ) + || SQL_ISRULE(pColumnRef,char_value_fct) + || SQL_ISRULE(pColumnRef,char_substring_fct) + || SQL_ISRULE(pColumnRef,position_exp) + || SQL_ISRULE(pColumnRef,fold) + || SQL_ISRULE(pColumnRef,length_exp) + || SQL_ISRULE(pColumnRef,num_value_exp) + || SQL_ISRULE(pColumnRef,term) + || SQL_ISRULE(pColumnRef,factor) + || SQL_ISRULE(pColumnRef,set_fct_spec) ) + { + ::rtl::Reference<OPredicateCompiler> pCompiler = new OPredicateCompiler(this); + pCompiler->setOrigColumns(m_aCompiler->getOrigColumns()); + ::rtl::Reference<OPredicateInterpreter> pInterpreter = new OPredicateInterpreter(pCompiler); + pCompiler->execute( pColumnRef ); + m_aSelectionEvaluations.push_back( TPredicates(pCompiler,pInterpreter) ); + } + else if ( SQL_ISRULE(pColumnRef,general_set_fct) && pColumnRef->count() != 4 ) + { + m_pConnection->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT,nullptr); + } + else + { + if ( SQL_ISPUNCTUATION( pColumnRef, "*" ) + || ( SQL_ISRULE( pColumnRef, column_ref ) + && ( pColumnRef->count() == 3 ) + && ( pColumnRef->getChild(0)->getNodeType() == SQLNodeType::Name ) + && SQL_ISPUNCTUATION( pColumnRef->getChild(1), "." ) + && SQL_ISRULE( pColumnRef->getChild(2), column_val ) + && SQL_ISPUNCTUATION( pColumnRef->getChild(2)->getChild(0), "*" ) + ) + ) + { + // push one element for each column of our table + const Reference< XNameAccess > xColumnNames( m_aCompiler->getOrigColumns() ); + const Sequence< OUString > aColumnNames( xColumnNames->getElementNames() ); + for ( sal_Int32 j=0; j<aColumnNames.getLength(); ++j ) + m_aSelectionEvaluations.push_back( TPredicates() ); + } + else + m_aSelectionEvaluations.push_back( TPredicates() ); + } + } + } + } + + m_aCompiler->start(pSQLParseNode); +} + + +void OSQLAnalyzer::bindRow(OCodeList& rCodeList,const OValueRefRow& _pRow) +{ + for (auto const& code : rCodeList) + { + OOperandAttr* pAttr = dynamic_cast<OOperandAttr*>(code.get()); + if (pAttr) + { + pAttr->bindValue(_pRow); + } + } +} + +void OSQLAnalyzer::bindSelectRow(const OValueRefRow& _pRow) +{ + // first the select part + for (auto const& selectionEval : m_aSelectionEvaluations) + { + if ( selectionEval.first.is() ) + bindRow(selectionEval.first->m_aCodeList,_pRow); + } +} + +void OSQLAnalyzer::bindEvaluationRow(OValueRefRow const & _pRow) +{ + bindRow(m_aCompiler->m_aCodeList,_pRow); +} + +OOperandAttr* OSQLAnalyzer::createOperandAttr(sal_Int32 _nPos, + const Reference< XPropertySet>& _xCol) +{ + return new OOperandAttr(static_cast<sal_uInt16>(_nPos),_xCol); +} + +bool OSQLAnalyzer::hasRestriction() const +{ + return m_aCompiler->hasCode(); +} + +bool OSQLAnalyzer::hasFunctions() const +{ + if ( m_bSelectionFirstTime ) + { + m_bSelectionFirstTime = false; + for (auto const& selectionEval : m_aSelectionEvaluations) + { + if ( selectionEval.first.is() ) + { + m_bHasSelectionCode = selectionEval.first->hasCode(); + if (m_bHasSelectionCode) + break; + } + } + } + return m_bHasSelectionCode; +} + +void OSQLAnalyzer::setSelectionEvaluationResult(OValueRefRow const & _pRow,const std::vector<sal_Int32>& _rColumnMapping) +{ + sal_Int32 nPos = 1; + for (auto const& selectionEval : m_aSelectionEvaluations) + { + if ( selectionEval.second.is() ) + { + // the first column (index 0) is for convenience only. The first real select column is no 1. + sal_Int32 map = nPos; + if ( nPos < static_cast< sal_Int32 >( _rColumnMapping.size() ) ) + map = _rColumnMapping[nPos]; + if ( map > 0 ) + selectionEval.second->startSelection( (*_pRow)[map] ); + } + ++nPos; + } +} + +void OSQLAnalyzer::dispose() +{ + m_aCompiler->dispose(); + for (auto const& selectionEval : m_aSelectionEvaluations) + { + if ( selectionEval.first.is() ) + selectionEval.first->dispose(); + } +} + +void OSQLAnalyzer::setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols) +{ + m_aCompiler->setOrigColumns(rCols); + for (auto const& selectionEval : m_aSelectionEvaluations) + { + if ( selectionEval.first.is() ) + selectionEval.first->setOrigColumns(rCols); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/fcode.cxx b/connectivity/source/drivers/file/fcode.cxx new file mode 100644 index 000000000..36cba4a73 --- /dev/null +++ b/connectivity/source/drivers/file/fcode.cxx @@ -0,0 +1,391 @@ +/* -*- 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 <file/fcode.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <connectivity/sqlparse.hxx> +#include <sqlbison.hxx> +#include <com/sun/star/sdb/SQLFilterOperator.hpp> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::file; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; + +OCode::~OCode() = default; + +OOperandRow::OOperandRow(sal_uInt16 _nPos, sal_Int32 _rType) + : OOperand(_rType) + , m_nRowPos(_nPos) +{} + +void OOperandRow::bindValue(const OValueRefRow& _pRow) +{ + OSL_ENSURE(_pRow.is(),"NO EMPTY row allowed!"); + m_pRow = _pRow; + OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()"); + (*m_pRow)[m_nRowPos]->setBound(true); +} + +void OOperandRow::setValue(const ORowSetValue& _rVal) +{ + OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()"); + (*(*m_pRow)[m_nRowPos]) = _rVal; +} + +const ORowSetValue& OOperandRow::getValue() const +{ + OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()"); + return (*m_pRow)[m_nRowPos]->getValue(); +} + + +void OOperandValue::setValue(const ORowSetValue& _rVal) +{ + m_aValue = _rVal; +} + +OOperandParam::OOperandParam(OSQLParseNode const * pNode, sal_Int32 _nPos) + : OOperandRow(static_cast<sal_uInt16>(_nPos), DataType::VARCHAR) // Standard-Type +{ + OSL_ENSURE(SQL_ISRULE(pNode,parameter),"Argument is not a parameter"); + OSL_ENSURE(pNode->count() > 0,"Error in Parse Tree"); + OSQLParseNode *pMark = pNode->getChild(0); + + OUString aParameterName; + if (SQL_ISPUNCTUATION(pMark, "?")) + aParameterName = "?"; + else if (SQL_ISPUNCTUATION(pMark, ":")) + aParameterName = pNode->getChild(1)->getTokenValue(); + else + { + SAL_WARN( "connectivity.drivers","Error in Parse Tree"); + } + + // set up Parameter-Column with default type, can be specified more precisely later using Describe-Parameter + + // save Identity (not especially necessary here, just for the sake of symmetry) + + // todo + // OColumn* pColumn = new OFILEColumn(aParameterName,eDBType,255,0,SQL_FLAGS_NULLALLOWED); + // rParamColumns->AddColumn(pColumn); + + // the value will be set just before the evaluation +} + + +const ORowSetValue& OOperandValue::getValue() const +{ + return m_aValue; +} + + +OOperandConst::OOperandConst(const OSQLParseNode& rColumnRef, const OUString& aStrValue) +{ + switch (rColumnRef.getNodeType()) + { + case SQLNodeType::String: + m_aValue = aStrValue; + m_eDBType = DataType::VARCHAR; + m_aValue.setBound(true); + return; + case SQLNodeType::IntNum: + case SQLNodeType::ApproxNum: + m_aValue = aStrValue.toDouble(); + m_eDBType = DataType::DOUBLE; + m_aValue.setBound(true); + return; + default: + break; + } + + if (SQL_ISTOKEN(&rColumnRef, TRUE)) + { + m_aValue = 1.0; + m_eDBType = DataType::BIT; + } + else if (SQL_ISTOKEN(&rColumnRef, FALSE)) + { + m_aValue = 0.0; + m_eDBType = DataType::BIT; + } + else + { + SAL_WARN( "connectivity.drivers", "Parse Error"); + } + m_aValue.setBound(true); +} + + +// Implementation of the operators + + +bool OBoolOperator::operate(const OOperand*, const OOperand*) const +{ + return false; +} + + +void OBoolOperator::Exec(OCodeStack& rCodeStack) +{ + OOperand *pRight = rCodeStack.top(); + rCodeStack.pop(); + OOperand *pLeft = rCodeStack.top(); + rCodeStack.pop(); + + rCodeStack.push(new OOperandResultBOOL(operate(pLeft, pRight))); + if( typeid(OOperandResult) == typeid(*pLeft)) + delete pLeft; + if( typeid(OOperandResult) == typeid(*pRight)) + delete pRight; +} + +bool OOp_NOT::operate(const OOperand* pLeft, const OOperand* ) const +{ + return !pLeft->isValid(); +} + +void OOp_NOT::Exec(OCodeStack& rCodeStack) +{ + OOperand* pOperand = rCodeStack.top(); + rCodeStack.pop(); + + rCodeStack.push(new OOperandResultBOOL(operate(pOperand, nullptr))); + + if( typeid(OOperandResult) == typeid(*pOperand)) + delete pOperand; +} + +bool OOp_AND::operate(const OOperand* pLeft, const OOperand* pRight) const +{ + return pLeft->isValid() && pRight->isValid(); +} + + +bool OOp_OR::operate(const OOperand* pLeft, const OOperand* pRight) const +{ + return pLeft->isValid() || pRight->isValid(); +} + + +void OOp_ISNULL::Exec(OCodeStack& rCodeStack) +{ + OOperand* pOperand = rCodeStack.top(); + rCodeStack.pop(); + + rCodeStack.push(new OOperandResultBOOL(operate(pOperand, nullptr))); + if( typeid(OOperandResult) == typeid(*pOperand)) + delete pOperand; +} + + +bool OOp_ISNULL::operate(const OOperand* pOperand, const OOperand*) const +{ + return pOperand->getValue().isNull(); +} + + +bool OOp_ISNOTNULL::operate(const OOperand* pOperand, const OOperand*) const +{ + return !OOp_ISNULL::operate(pOperand, nullptr); +} + + +bool OOp_LIKE::operate(const OOperand* pLeft, const OOperand* pRight) const +{ + bool bMatch; + const ORowSetValue& aLH(pLeft->getValue()); + const ORowSetValue& aRH(pRight->getValue()); + + if (aLH.isNull() || aRH.isNull()) + bMatch = false; + else + { + bMatch = match(aRH.getString(), aLH.getString(), cEscape); + } + return bMatch; +} + + +bool OOp_NOTLIKE::operate(const OOperand* pLeft, const OOperand* pRight) const +{ + return !OOp_LIKE::operate(pLeft, pRight); +} + + +bool OOp_COMPARE::operate(const OOperand* pLeft, const OOperand* pRight) const +{ + const ORowSetValue& aLH(pLeft->getValue()); + const ORowSetValue& aRH(pRight->getValue()); + + if (aLH.isNull() || aRH.isNull()) // if (!aLH.getValue() || !aRH.getValue()) + return false; + + bool bResult = false; + sal_Int32 eDBType = pLeft->getDBType(); + + // Comparison (depending on Data-type): + switch (eDBType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + { + OUString sLH = aLH, sRH = aRH; + sal_Int32 nRes = sLH.compareToIgnoreAsciiCase(sRH); + switch(aPredicateType) + { + case SQLFilterOperator::EQUAL: bResult = (nRes == 0); break; + case SQLFilterOperator::NOT_EQUAL: bResult = (nRes != 0); break; + case SQLFilterOperator::LESS: bResult = (nRes < 0); break; + case SQLFilterOperator::LESS_EQUAL: bResult = (nRes <= 0); break; + case SQLFilterOperator::GREATER: bResult = (nRes > 0); break; + case SQLFilterOperator::GREATER_EQUAL: bResult = (nRes >= 0); break; + default: bResult = false; + } + } break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::BIT: + case DataType::TIMESTAMP: + case DataType::DATE: + case DataType::TIME: + { + double n = aLH ,m = aRH; + + switch (aPredicateType) + { + case SQLFilterOperator::EQUAL: bResult = (n == m); break; + case SQLFilterOperator::LIKE: bResult = (n == m); break; + case SQLFilterOperator::NOT_EQUAL: bResult = (n != m); break; + case SQLFilterOperator::NOT_LIKE: bResult = (n != m); break; + case SQLFilterOperator::LESS: bResult = (n < m); break; + case SQLFilterOperator::LESS_EQUAL: bResult = (n <= m); break; + case SQLFilterOperator::GREATER: bResult = (n > m); break; + case SQLFilterOperator::GREATER_EQUAL: bResult = (n >= m); break; + default: bResult = false; + } + } break; + default: + bResult = aLH == aRH; + } + return bResult; +} + + +void ONumOperator::Exec(OCodeStack& rCodeStack) +{ + OOperand *pRight = rCodeStack.top(); + rCodeStack.pop(); + OOperand *pLeft = rCodeStack.top(); + rCodeStack.pop(); + + rCodeStack.push(new OOperandResultNUM(operate(pLeft->getValue(), pRight->getValue()))); + if( typeid(OOperandResult) == typeid(*pLeft)) + delete pLeft; + if( typeid(OOperandResult) == typeid(*pRight)) + delete pRight; +} + +double OOp_ADD::operate(const double& fLeft,const double& fRight) const +{ + return fLeft + fRight; +} + + +double OOp_SUB::operate(const double& fLeft,const double& fRight) const +{ + return fLeft - fRight; +} + + +double OOp_MUL::operate(const double& fLeft,const double& fRight) const +{ + return fLeft * fRight; +} + + +double OOp_DIV::operate(const double& fLeft,const double& fRight) const +{ + return fLeft / fRight; +} + +void ONthOperator::Exec(OCodeStack& rCodeStack) +{ + std::vector<ORowSetValue> aValues; + std::vector<OOperand*> aOperands; + OOperand* pOperand; + do + { + OSL_ENSURE(!rCodeStack.empty(),"Stack must be none empty!"); + pOperand = rCodeStack.top(); + rCodeStack.pop(); + assert(pOperand); + if (pOperand && typeid(OStopOperand) != typeid(*pOperand)) + aValues.push_back( pOperand->getValue() ); + aOperands.push_back( pOperand ); + } + while (pOperand && typeid(OStopOperand) != typeid(*pOperand)); + + rCodeStack.push(new OOperandResult(operate(aValues))); + + for (const auto& rpOperand : aOperands) + { + if (typeid(OOperandResult) == typeid(*rpOperand)) + delete rpOperand; + } +} + +void OBinaryOperator::Exec(OCodeStack& rCodeStack) +{ + OOperand *pRight = rCodeStack.top(); + rCodeStack.pop(); + OOperand *pLeft = rCodeStack.top(); + rCodeStack.pop(); + + if ( !rCodeStack.empty() && typeid(OStopOperand) == typeid(*rCodeStack.top()) ) + rCodeStack.pop(); + + rCodeStack.push(new OOperandResult(operate(pLeft->getValue(),pRight->getValue()))); + if(typeid(OOperandResult) == typeid(*pRight)) + delete pRight; + if(typeid(OOperandResult) == typeid(*pLeft)) + delete pLeft; +} + +void OUnaryOperator::Exec(OCodeStack& rCodeStack) +{ + OSL_ENSURE(!rCodeStack.empty(),"Stack is empty!"); + OOperand* pOperand = rCodeStack.top(); + rCodeStack.pop(); + + rCodeStack.push(new OOperandResult(operate(pOperand->getValue()))); + if (typeid(OOperandResult) == typeid(*pOperand)) + delete pOperand; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/fcomp.cxx b/connectivity/source/drivers/file/fcomp.cxx new file mode 100644 index 000000000..134565e3e --- /dev/null +++ b/connectivity/source/drivers/file/fcomp.cxx @@ -0,0 +1,890 @@ +/* -*- 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 <file/fcomp.hxx> +#include <tools/debug.hxx> +#include <connectivity/sqlparse.hxx> +#include <file/fanalyzer.hxx> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbconversion.hxx> +#include <com/sun/star/sdb/SQLFilterOperator.hpp> +#include <file/FStringFunctions.hxx> +#include <file/FDateFunctions.hxx> +#include <file/FNumericFunctions.hxx> +#include <file/FConnection.hxx> +#include <sqlbison.hxx> +#include <strings.hrc> + +using namespace connectivity; +using namespace connectivity::file; +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdb; +using namespace ::com::sun::star::container; +using namespace com::sun::star; + +OPredicateCompiler::OPredicateCompiler(OSQLAnalyzer* pAnalyzer)//,OCursor& rCurs) + : m_pAnalyzer(pAnalyzer) + , m_nParamCounter(0) +{ +} + + +OPredicateCompiler::~OPredicateCompiler() +{ + Clean(); +} + +void OPredicateCompiler::dispose() +{ + Clean(); + m_orgColumns = nullptr; +} + +void OPredicateCompiler::start(OSQLParseNode const * pSQLParseNode) +{ + if (!pSQLParseNode) + return; + + m_nParamCounter = 0; + // analyse Parse Tree (depending on Statement-type) + // and set pointer on WHERE-clause: + OSQLParseNode * pWhereClause = nullptr; + + if (SQL_ISRULE(pSQLParseNode,select_statement)) + { + OSQLParseNode * pOrderbyClause = nullptr; + DBG_ASSERT(pSQLParseNode->count() >= 4,"OFILECursor: Error in Parse Tree"); + + OSQLParseNode * pTableExp = pSQLParseNode->getChild(3); + DBG_ASSERT(pTableExp != nullptr,"Error in Parse Tree"); + DBG_ASSERT(SQL_ISRULE(pTableExp,table_exp)," Error in Parse Tree"); + DBG_ASSERT(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"Error in Parse Tree"); + + // check that we don't use anything other than count(*) as function + OSQLParseNode* pSelection = pSQLParseNode->getChild(2); + if ( SQL_ISRULE(pSelection,scalar_exp_commalist) ) + { + for (size_t i = 0; i < pSelection->count(); i++) + { + OSQLParseNode *pColumnRef = pSelection->getChild(i)->getChild(0); + if ( SQL_ISRULE(pColumnRef,general_set_fct) && pColumnRef->count() != 4 ) + { + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT,nullptr); + } + } + } + + + pWhereClause = pTableExp->getChild(1); + pOrderbyClause = pTableExp->getChild(ORDER_BY_CHILD_POS); + (void)pOrderbyClause; + } + else if (SQL_ISRULE(pSQLParseNode,update_statement_searched)) + { + DBG_ASSERT(pSQLParseNode->count() == 5,"OFILECursor: Error in Parse Tree"); + pWhereClause = pSQLParseNode->getChild(4); + } + else if (SQL_ISRULE(pSQLParseNode,delete_statement_searched)) + { + DBG_ASSERT(pSQLParseNode->count() == 4,"Error in Parse Tree"); + pWhereClause = pSQLParseNode->getChild(3); + } + else + // Other Statement. no selection-criteria + return; + + if (SQL_ISRULE(pWhereClause,where_clause)) + { + // a where-clause is not allowed to be empty: + DBG_ASSERT(pWhereClause->count() == 2,"OFILECursor: Error in Parse Tree"); + + OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1); + DBG_ASSERT(pComparisonPredicate != nullptr,"OFILECursor: Error in Parse Tree"); + + execute( pComparisonPredicate ); + } + else + { + // The where-clause is optionally in the majority of cases, i.e. it might be an "optional-where-clause". + DBG_ASSERT(SQL_ISRULE(pWhereClause,opt_where_clause),"OPredicateCompiler: Error in Parse Tree"); + } +} + + +OOperand* OPredicateCompiler::execute(OSQLParseNode const * pPredicateNode) +{ + OOperand* pOperand = nullptr; + if (pPredicateNode->count() == 3 && // Expression is bracketed + SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"(") && + SQL_ISPUNCTUATION(pPredicateNode->getChild(2),")")) + { + execute(pPredicateNode->getChild(1)); + } + else if ((SQL_ISRULE(pPredicateNode,search_condition) || SQL_ISRULE(pPredicateNode,boolean_term)) + && // AND/OR-linkage: + pPredicateNode->count() == 3) + { + execute(pPredicateNode->getChild(0)); // process the left branch + execute(pPredicateNode->getChild(2)); // process the right branch + + if (SQL_ISTOKEN(pPredicateNode->getChild(1),OR)) // OR-Operator + { + m_aCodeList.emplace_back(new OOp_OR); + } + else if (SQL_ISTOKEN(pPredicateNode->getChild(1),AND)) // AND-Operator + m_aCodeList.emplace_back(new OOp_AND); + else + { + OSL_FAIL("OPredicateCompiler: Error in Parse Tree"); + } + } + else if (SQL_ISRULE(pPredicateNode,boolean_factor)) + { + execute(pPredicateNode->getChild(1)); + m_aCodeList.emplace_back(new OOp_NOT); + } + else if (SQL_ISRULE(pPredicateNode,comparison_predicate)) + { + execute_COMPARE(pPredicateNode); + } + else if (SQL_ISRULE(pPredicateNode,like_predicate)) + { + execute_LIKE(pPredicateNode); + } + else if (SQL_ISRULE(pPredicateNode,between_predicate)) + { + execute_BETWEEN(pPredicateNode); + } + else if (SQL_ISRULE(pPredicateNode,test_for_null)) + { + execute_ISNULL(pPredicateNode); + } + else if(SQL_ISRULE(pPredicateNode,num_value_exp)) + { + execute(pPredicateNode->getChild(0)); // process the left branch + execute(pPredicateNode->getChild(2)); // process the right branch + if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"+")) + { + m_aCodeList.emplace_back(new OOp_ADD); + } + else if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"-")) + m_aCodeList.emplace_back(new OOp_SUB); + else + { + OSL_FAIL("OPredicateCompiler: Error in Parse Tree num_value_exp"); + } + } + else if(SQL_ISRULE(pPredicateNode,term)) + { + execute(pPredicateNode->getChild(0)); // process the left branch + execute(pPredicateNode->getChild(2)); // process the right branch + if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"*")) + { + m_aCodeList.emplace_back(new OOp_MUL); + } + else if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"/")) + m_aCodeList.emplace_back(new OOp_DIV); + else + { + OSL_FAIL("OPredicateCompiler: Error in Parse Tree num_value_exp"); + } + } + else + pOperand = execute_Operand(pPredicateNode); // now only simple operands will be processed + + return pOperand; +} + + +void OPredicateCompiler::execute_COMPARE(OSQLParseNode const * pPredicateNode) +{ + DBG_ASSERT(pPredicateNode->count() == 3,"OFILECursor: Error in Parse Tree"); + + if ( !(SQL_ISRULE(pPredicateNode->getChild(0),column_ref) || + pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::String || + pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::IntNum || + pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::ApproxNum || + SQL_ISTOKEN(pPredicateNode->getChild(2),TRUE) || + SQL_ISTOKEN(pPredicateNode->getChild(2),FALSE) || + SQL_ISRULE(pPredicateNode->getChild(2),parameter) || + // odbc date + SQL_ISRULE(pPredicateNode->getChild(2),set_fct_spec) || + SQL_ISRULE(pPredicateNode->getChild(2),position_exp) || + SQL_ISRULE(pPredicateNode->getChild(2),char_substring_fct) || + // upper, lower etc. + SQL_ISRULE(pPredicateNode->getChild(2),fold)) ) + { + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr); + return; + } + + sal_Int32 ePredicateType( SQLFilterOperator::EQUAL ); + OSQLParseNode *pPrec = pPredicateNode->getChild(1); + + if (pPrec->getNodeType() == SQLNodeType::Equal) + ePredicateType = SQLFilterOperator::EQUAL; + else if (pPrec->getNodeType() == SQLNodeType::NotEqual) + ePredicateType = SQLFilterOperator::NOT_EQUAL; + else if (pPrec->getNodeType() == SQLNodeType::Less) + ePredicateType = SQLFilterOperator::LESS; + else if (pPrec->getNodeType() == SQLNodeType::LessEq) + ePredicateType = SQLFilterOperator::LESS_EQUAL; + else if (pPrec->getNodeType() == SQLNodeType::GreatEq) + ePredicateType = SQLFilterOperator::GREATER_EQUAL; + else if (pPrec->getNodeType() == SQLNodeType::Great) + ePredicateType = SQLFilterOperator::GREATER; + else + OSL_FAIL( "OPredicateCompiler::execute_COMPARE: unexpected node type!" ); + + execute(pPredicateNode->getChild(0)); + execute(pPredicateNode->getChild(2)); + m_aCodeList.emplace_back( new OOp_COMPARE(ePredicateType) ); +} + + +void OPredicateCompiler::execute_LIKE(OSQLParseNode const * pPredicateNode) +{ + DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree"); + const OSQLParseNode* pPart2 = pPredicateNode->getChild(1); + + sal_Unicode cEscape = L'\0'; + const bool bNotLike = pPart2->getChild(0)->isToken(); + + OSQLParseNode* pAtom = pPart2->getChild(pPart2->count()-2); + OSQLParseNode* pOptEscape = pPart2->getChild(pPart2->count()-1); + + if (!(pAtom->getNodeType() == SQLNodeType::String || + SQL_ISRULE(pAtom,parameter) || + // odbc date + SQL_ISRULE(pAtom,set_fct_spec) || + SQL_ISRULE(pAtom,position_exp) || + SQL_ISRULE(pAtom,char_substring_fct) || + // upper, lower etc. + SQL_ISRULE(pAtom,fold)) ) + { + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr); + return; + } + + if (pOptEscape->count() != 0) + { + if (pOptEscape->count() != 2) + { + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,nullptr); + } + OSQLParseNode *pEscNode = pOptEscape->getChild(1); + if (pEscNode->getNodeType() != SQLNodeType::String) + { + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,nullptr); + } + else + cEscape = pEscNode->getTokenValue().toChar(); + } + + execute(pPredicateNode->getChild(0)); + execute(pAtom); + + OBoolOperator* pOperator = bNotLike + ? new OOp_NOTLIKE(cEscape) + : new OOp_LIKE(cEscape); + m_aCodeList.emplace_back(pOperator); +} + +void OPredicateCompiler::execute_BETWEEN(OSQLParseNode const * pPredicateNode) +{ + DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree"); + + OSQLParseNode* pColumn = pPredicateNode->getChild(0); + const OSQLParseNode* pPart2 = pPredicateNode->getChild(1); + OSQLParseNode* p1stValue = pPart2->getChild(2); + OSQLParseNode* p2ndtValue = pPart2->getChild(4); + + if ( + !(p1stValue->getNodeType() == SQLNodeType::String || SQL_ISRULE(p1stValue,parameter)) + && !(p2ndtValue->getNodeType() == SQLNodeType::String || SQL_ISRULE(p2ndtValue,parameter)) + ) + { + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_BETWEEN,nullptr); + } + + bool bNot = SQL_ISTOKEN(pPart2->getChild(0),NOT); + + OOperand* pColumnOp = execute(pColumn); + OOperand* pOb1 = execute(p1stValue); + OBoolOperator* pOperator = new OOp_COMPARE(bNot ? SQLFilterOperator::LESS_EQUAL : SQLFilterOperator::GREATER); + m_aCodeList.emplace_back(pOperator); + + execute(pColumn); + OOperand* pOb2 = execute(p2ndtValue); + pOperator = new OOp_COMPARE(bNot ? SQLFilterOperator::GREATER_EQUAL : SQLFilterOperator::LESS); + m_aCodeList.emplace_back(pOperator); + + if ( pColumnOp && pOb1 && pOb2 ) + { + switch(pColumnOp->getDBType()) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + pOb1->setValue(pOb1->getValue().getString()); + pOb2->setValue(pOb2->getValue().getString()); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + pOb1->setValue(static_cast<double>(pOb1->getValue())); + pOb2->setValue(static_cast<double>(pOb2->getValue())); + break; + case DataType::FLOAT: + pOb1->setValue(static_cast<float>(pOb1->getValue())); + pOb2->setValue(static_cast<float>(pOb2->getValue())); + break; + case DataType::DOUBLE: + case DataType::REAL: + pOb1->setValue(static_cast<double>(pOb1->getValue())); + pOb2->setValue(static_cast<double>(pOb2->getValue())); + break; + case DataType::DATE: + pOb1->setValue(static_cast<util::Date>(pOb1->getValue())); + pOb2->setValue(static_cast<util::Date>(pOb2->getValue())); + break; + case DataType::TIME: + pOb1->setValue(static_cast<util::Time>(pOb1->getValue())); + pOb2->setValue(static_cast<util::Time>(pOb2->getValue())); + break; + case DataType::TIMESTAMP: + pOb1->setValue(static_cast<util::DateTime>(pOb1->getValue())); + pOb2->setValue(static_cast<util::DateTime>(pOb2->getValue())); + break; + } + } + + + OBoolOperator* pBoolOp = nullptr; + if ( bNot ) + pBoolOp = new OOp_OR; + else + pBoolOp = new OOp_AND; + m_aCodeList.emplace_back(pBoolOp); +} + +void OPredicateCompiler::execute_ISNULL(OSQLParseNode const * pPredicateNode) +{ + DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree"); + const OSQLParseNode* pPart2 = pPredicateNode->getChild(1); + DBG_ASSERT(SQL_ISTOKEN(pPart2->getChild(0),IS),"OFILECursor: Error in Parse Tree"); + + sal_Int32 ePredicateType; + if (SQL_ISTOKEN(pPart2->getChild(1),NOT)) + ePredicateType = SQLFilterOperator::NOT_SQLNULL; + else + ePredicateType = SQLFilterOperator::SQLNULL; + + execute(pPredicateNode->getChild(0)); + OBoolOperator* pOperator = (ePredicateType == SQLFilterOperator::SQLNULL) ? + new OOp_ISNULL : new OOp_ISNOTNULL; + m_aCodeList.emplace_back(pOperator); +} + +OOperand* OPredicateCompiler::execute_Operand(OSQLParseNode const * pPredicateNode) +{ + OOperand* pOperand = nullptr; + + if (SQL_ISRULE(pPredicateNode,column_ref)) + { + OUString aColumnName; + if (pPredicateNode->count() == 1) + { + aColumnName = pPredicateNode->getChild(0)->getTokenValue(); + } + else if (pPredicateNode->count() == 3) + { + if(SQL_ISRULE(pPredicateNode->getChild(2),column_val)) + aColumnName = pPredicateNode->getChild(2)->getChild(0)->getTokenValue(); + else + aColumnName = pPredicateNode->getChild(2)->getTokenValue(); + } + + if(!m_orgColumns->hasByName(aColumnName)) + { + const OUString sError( m_pAnalyzer->getConnection()->getResources().getResourceStringWithSubstitution( + STR_INVALID_COLUMNNAME, + "$columnname$", aColumnName + ) ); + ::dbtools::throwGenericSQLException( sError, nullptr ); + } + css::uno::Reference< css::beans::XPropertySet> xCol; + try + { + if (m_orgColumns->getByName(aColumnName) >>= xCol) + { + pOperand = OSQLAnalyzer::createOperandAttr(Reference< XColumnLocate>(m_orgColumns,UNO_QUERY_THROW)->findColumn(aColumnName),xCol); + } + else + {// Column doesn't exist in the Result-set + const OUString sError( m_pAnalyzer->getConnection()->getResources().getResourceStringWithSubstitution( + STR_INVALID_COLUMNNAME, + "$columnname$", aColumnName + ) ); + ::dbtools::throwGenericSQLException( sError, nullptr ); + } + } + catch(Exception &) + { + OSL_FAIL("OPredicateCompiler::execute_Operand Exception"); + } + } + else if (SQL_ISRULE(pPredicateNode,parameter)) + { + pOperand = new OOperandParam(pPredicateNode, ++m_nParamCounter); + } + else if (pPredicateNode->getNodeType() == SQLNodeType::String || + pPredicateNode->getNodeType() == SQLNodeType::IntNum || + pPredicateNode->getNodeType() == SQLNodeType::ApproxNum || + pPredicateNode->getNodeType() == SQLNodeType::Name || + SQL_ISTOKEN(pPredicateNode,TRUE) || + SQL_ISTOKEN(pPredicateNode,FALSE) || + SQL_ISRULE(pPredicateNode,parameter)) + { + pOperand = new OOperandConst(*pPredicateNode, pPredicateNode->getTokenValue()); + } + else if((pPredicateNode->count() == 2) && + (SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"+") || SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"-")) && + pPredicateNode->getChild(1)->getNodeType() == SQLNodeType::IntNum) + { // if -1 or +1 is there + OUString aValue = pPredicateNode->getChild(0)->getTokenValue() + pPredicateNode->getChild(1)->getTokenValue(); + pOperand = new OOperandConst(*pPredicateNode->getChild(1), aValue); + } + else if( SQL_ISRULE(pPredicateNode,set_fct_spec) && SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"{") ) + { + const OSQLParseNode* pODBCNode = pPredicateNode->getChild(1); + const OSQLParseNode* pODBCNodeChild = pODBCNode->getChild(0); + + // Odbc Date or time + if (pODBCNodeChild->getNodeType() == SQLNodeType::Keyword && ( + SQL_ISTOKEN(pODBCNodeChild,D) || + SQL_ISTOKEN(pODBCNodeChild,T) || + SQL_ISTOKEN(pODBCNodeChild,TS) )) + { + OUString sDateTime = pODBCNode->getChild(1)->getTokenValue(); + pOperand = new OOperandConst(*pODBCNode->getChild(1), sDateTime); + if(SQL_ISTOKEN(pODBCNodeChild,D)) + { + pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(sDateTime))); + } + else if(SQL_ISTOKEN(pODBCNodeChild,T)) + { + pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(sDateTime))); + } + else if(SQL_ISTOKEN(pODBCNodeChild,TS)) + { + pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(sDateTime))); + } + } + else + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr); + + } + else if( SQL_ISRULE(pPredicateNode,fold) ) + { + execute_Fold(pPredicateNode); + } + else if( SQL_ISRULE(pPredicateNode,set_fct_spec) + || SQL_ISRULE(pPredicateNode,position_exp) + || SQL_ISRULE(pPredicateNode,char_substring_fct) + ) + { + executeFunction(pPredicateNode); + } + else if( SQL_ISRULE(pPredicateNode,length_exp) ) + { + executeFunction(pPredicateNode->getChild(0)); + } + else + { + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr); + } + if (pOperand) + m_aCodeList.emplace_back(pOperand); + return pOperand; +} + + +bool OPredicateInterpreter::evaluate(OCodeList& rCodeList) +{ + static bool bResult; + + if (!(rCodeList[0])) + return true; // no Predicate + + for (auto const& code : rCodeList) + { + OOperand* pOperand = dynamic_cast<OOperand* >(code.get()); + if (pOperand) + m_aStack.push(pOperand); + else + static_cast<OOperator *>(code.get())->Exec(m_aStack); + } + + OOperand* pOperand = m_aStack.top(); + m_aStack.pop(); + + DBG_ASSERT(m_aStack.empty(), "Stack error"); + DBG_ASSERT(pOperand, "Stack error"); + + bResult = pOperand->isValid(); + if (typeid(OOperandResult) == typeid(*pOperand)) + delete pOperand; + return bResult; +} + +void OPredicateInterpreter::evaluateSelection(OCodeList& rCodeList, ORowSetValueDecoratorRef const & _rVal) +{ + if (!(rCodeList[0])) + return ; // no Predicate + + for (auto const& code : rCodeList) + { + OOperand* pOperand = dynamic_cast<OOperand* >(code.get()); + if (pOperand) + m_aStack.push(pOperand); + else + static_cast<OOperator *>(code.get())->Exec(m_aStack); + } + + OOperand* pOperand = m_aStack.top(); + m_aStack.pop(); + + DBG_ASSERT(m_aStack.empty(), "Stack error"); + DBG_ASSERT(pOperand, "Stack error"); + + (*_rVal) = pOperand->getValue(); + if (typeid(OOperandResult) == typeid(*pOperand)) + delete pOperand; +} + +void OPredicateCompiler::execute_Fold(OSQLParseNode const * pPredicateNode) +{ + DBG_ASSERT(pPredicateNode->count() >= 4,"OFILECursor: Error in Parse Tree"); + + bool bUpper = SQL_ISTOKEN(pPredicateNode->getChild(0),UPPER); + + execute(pPredicateNode->getChild(2)); + OOperator* pOperator = nullptr; + if ( bUpper ) + pOperator = new OOp_Upper; + else + pOperator = new OOp_Lower; + + m_aCodeList.emplace_back(pOperator); +} + +void OPredicateCompiler::executeFunction(OSQLParseNode const * pPredicateNode) +{ + OOperator* pOperator = nullptr; + + OSL_ENSURE(pPredicateNode->getChild(0)->isToken(),"The first one must be the name of the function!"); + sal_Int32 nTokenId = pPredicateNode->getChild(0)->getTokenID(); + switch ( nTokenId ) + { + case SQL_TOKEN_CHAR_LENGTH: + case SQL_TOKEN_LENGTH: + case SQL_TOKEN_OCTET_LENGTH: + case SQL_TOKEN_ASCII: + case SQL_TOKEN_LCASE: + case SQL_TOKEN_LTRIM: + case SQL_TOKEN_RTRIM: + case SQL_TOKEN_SPACE: + case SQL_TOKEN_UCASE: + case SQL_TOKEN_ABS: + case SQL_TOKEN_ACOS: + case SQL_TOKEN_ASIN: + case SQL_TOKEN_ATAN: + case SQL_TOKEN_CEILING: + case SQL_TOKEN_COS: + case SQL_TOKEN_DEGREES: + case SQL_TOKEN_EXP: + case SQL_TOKEN_FLOOR: + case SQL_TOKEN_LOG10: + case SQL_TOKEN_LN: + case SQL_TOKEN_RADIANS: + case SQL_TOKEN_SIGN: + case SQL_TOKEN_SIN: + case SQL_TOKEN_SQRT: + case SQL_TOKEN_TAN: + case SQL_TOKEN_DAYNAME: + case SQL_TOKEN_DAYOFMONTH: + case SQL_TOKEN_DAYOFWEEK: + case SQL_TOKEN_DAYOFYEAR: + case SQL_TOKEN_HOUR: + case SQL_TOKEN_MINUTE: + case SQL_TOKEN_MONTH: + case SQL_TOKEN_MONTHNAME: + case SQL_TOKEN_QUARTER: + case SQL_TOKEN_SECOND: + case SQL_TOKEN_YEAR: + + execute(pPredicateNode->getChild(2)); + + switch( nTokenId ) + { + case SQL_TOKEN_CHAR_LENGTH: + case SQL_TOKEN_LENGTH: + case SQL_TOKEN_OCTET_LENGTH: + pOperator = new OOp_CharLength; + break; + case SQL_TOKEN_ASCII: + pOperator = new OOp_Ascii; + break; + case SQL_TOKEN_LCASE: + pOperator = new OOp_Lower; + break; + + case SQL_TOKEN_LTRIM: + pOperator = new OOp_LTrim; + break; + case SQL_TOKEN_RTRIM: + pOperator = new OOp_RTrim; + break; + case SQL_TOKEN_SPACE: + pOperator = new OOp_Space; + break; + case SQL_TOKEN_UCASE: + pOperator = new OOp_Upper; + break; + case SQL_TOKEN_ABS: + pOperator = new OOp_Abs; + break; + case SQL_TOKEN_ACOS: + pOperator = new OOp_ACos; + break; + case SQL_TOKEN_ASIN: + pOperator = new OOp_ASin; + break; + case SQL_TOKEN_ATAN: + pOperator = new OOp_ATan; + break; + case SQL_TOKEN_CEILING: + pOperator = new OOp_Ceiling; + break; + case SQL_TOKEN_COS: + pOperator = new OOp_Cos; + break; + case SQL_TOKEN_DEGREES: + pOperator = new OOp_Degrees; + break; + case SQL_TOKEN_EXP: + pOperator = new OOp_Exp; + break; + case SQL_TOKEN_FLOOR: + pOperator = new OOp_Floor; + break; + case SQL_TOKEN_LOG10: + pOperator = new OOp_Log10; + break; + case SQL_TOKEN_LN: + pOperator = new OOp_Ln; + break; + case SQL_TOKEN_RADIANS: + pOperator = new OOp_Radians; + break; + case SQL_TOKEN_SIGN: + pOperator = new OOp_Sign; + break; + case SQL_TOKEN_SIN: + pOperator = new OOp_Sin; + break; + case SQL_TOKEN_SQRT: + pOperator = new OOp_Sqrt; + break; + case SQL_TOKEN_TAN: + pOperator = new OOp_Tan; + break; + case SQL_TOKEN_DAYOFWEEK: + pOperator = new OOp_DayOfWeek; + break; + case SQL_TOKEN_DAYOFMONTH: + pOperator = new OOp_DayOfMonth; + break; + case SQL_TOKEN_DAYOFYEAR: + pOperator = new OOp_DayOfYear; + break; + case SQL_TOKEN_MONTH: + pOperator = new OOp_Month; + break; + case SQL_TOKEN_DAYNAME: + pOperator = new OOp_DayName; + break; + case SQL_TOKEN_MONTHNAME: + pOperator = new OOp_MonthName; + break; + case SQL_TOKEN_QUARTER: + pOperator = new OOp_Quarter; + break; + case SQL_TOKEN_YEAR: + pOperator = new OOp_Year; + break; + case SQL_TOKEN_HOUR: + pOperator = new OOp_Hour; + break; + case SQL_TOKEN_MINUTE: + pOperator = new OOp_Minute; + break; + case SQL_TOKEN_SECOND: + pOperator = new OOp_Second; + break; + default: + OSL_FAIL("Error in switch!"); + } + break; + case SQL_TOKEN_CHAR: + case SQL_TOKEN_CONCAT: + case SQL_TOKEN_INSERT: + case SQL_TOKEN_LEFT: + case SQL_TOKEN_LOCATE: + case SQL_TOKEN_LOCATE_2: + case SQL_TOKEN_REPEAT: + case SQL_TOKEN_REPLACE: + case SQL_TOKEN_RIGHT: + case SQL_TOKEN_MOD: + case SQL_TOKEN_ROUND: + case SQL_TOKEN_LOGF: + case SQL_TOKEN_LOG: + case SQL_TOKEN_POWER: + case SQL_TOKEN_ATAN2: + case SQL_TOKEN_PI: + case SQL_TOKEN_CURDATE: + case SQL_TOKEN_CURTIME: + case SQL_TOKEN_NOW: + case SQL_TOKEN_WEEK: + { + m_aCodeList.emplace_back(new OStopOperand); + OSQLParseNode* pList = pPredicateNode->getChild(2); + for (size_t i=0; i < pList->count(); ++i) + execute(pList->getChild(i)); + + switch( nTokenId ) + { + case SQL_TOKEN_CHAR: + pOperator = new OOp_Char; + break; + case SQL_TOKEN_CONCAT: + pOperator = new OOp_Concat; + break; + case SQL_TOKEN_INSERT: + pOperator = new OOp_Insert; + break; + case SQL_TOKEN_LEFT: + pOperator = new OOp_Left; + break; + case SQL_TOKEN_LOCATE: + case SQL_TOKEN_LOCATE_2: + pOperator = new OOp_Locate; + break; + case SQL_TOKEN_REPEAT: + pOperator = new OOp_Repeat; + break; + case SQL_TOKEN_REPLACE: + pOperator = new OOp_Replace; + break; + case SQL_TOKEN_RIGHT: + pOperator = new OOp_Right; + break; + case SQL_TOKEN_MOD: + pOperator = new OOp_Mod; + break; + case SQL_TOKEN_ROUND: + pOperator = new OOp_Round; + break; + case SQL_TOKEN_LOGF: + case SQL_TOKEN_LOG: + pOperator = new OOp_Log; + break; + case SQL_TOKEN_POWER: + pOperator = new OOp_Pow; + break; + case SQL_TOKEN_ATAN2: + pOperator = new OOp_ATan2; + break; + case SQL_TOKEN_PI: + pOperator = new OOp_Pi; + break; + case SQL_TOKEN_CURDATE: + pOperator = new OOp_CurDate; + break; + case SQL_TOKEN_CURTIME: + pOperator = new OOp_CurTime; + break; + case SQL_TOKEN_NOW: + pOperator = new OOp_Now; + break; + case SQL_TOKEN_WEEK: + pOperator = new OOp_Week; + break; + default: + OSL_FAIL("Error in switch!"); + } + } + break; + + case SQL_TOKEN_SUBSTRING: + m_aCodeList.emplace_back(new OStopOperand); + if ( pPredicateNode->count() == 4 ) //char_substring_fct + { + OSQLParseNode* pList = pPredicateNode->getChild(2); + for (size_t i=0; i < pList->count(); ++i) + execute(pList->getChild(i)); + } + else + { + execute(pPredicateNode->getChild(2)); + execute(pPredicateNode->getChild(4)); + execute(pPredicateNode->getChild(5)->getChild(1)); + } + pOperator = new OOp_SubString; + break; + + case SQL_TOKEN_POSITION: + m_aCodeList.emplace_back(new OStopOperand); + if ( pPredicateNode->count() == 4 ) //position_exp + { + OSQLParseNode* pList = pPredicateNode->getChild(2); + for (size_t i=0; i < pList->count(); ++i) + execute(pList->getChild(i)); + } + else + { + execute(pPredicateNode->getChild(2)); + execute(pPredicateNode->getChild(4)); + } + pOperator = new OOp_Locate; + break; + default: + m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_FUNCTION_NOT_SUPPORTED,nullptr); + } + + m_aCodeList.emplace_back(pOperator); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/file/quotedstring.cxx b/connectivity/source/drivers/file/quotedstring.cxx new file mode 100644 index 000000000..f654c709e --- /dev/null +++ b/connectivity/source/drivers/file/quotedstring.cxx @@ -0,0 +1,146 @@ +/* -*- 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 <file/quotedstring.hxx> +#include <rtl/ustrbuf.hxx> + +namespace connectivity +{ + + sal_Int32 QuotedTokenizedString::GetTokenCount( sal_Unicode cTok, sal_Unicode cStrDel ) const + { + const sal_Int32 nLen = m_sString.getLength(); + if ( !nLen ) + return 0; + + sal_Int32 nTokCount = 1; + bool bStart = true; // Are we on the first character in the Token? + bool bInString = false; // Are we WITHIN a (cStrDel delimited) String? + + // Search for String-end after the first not matching character + for( sal_Int32 i = 0; i < nLen; ++i ) + { + const sal_Unicode cChar = m_sString[i]; + if (bStart) + { + bStart = false; + // First character a String-Delimiter? + if ( cChar == cStrDel ) + { + bInString = true; // then we are now WITHIN the string! + continue; // skip this character! + } + } + + if (bInString) + { + // when now the String-Delimiter-character occurs... + if ( cChar == cStrDel ) + { + if ((i+1 < nLen) && (m_sString[i+1] == cStrDel)) + { + // double String-Delimiter-character: + ++i; // no string-end, skip next character. + } + else + { + // String-End + bInString = false; + } + } + } // if (bInString) + else + { + // does the Token-character match, then raise TokCount + if ( cChar == cTok ) + { + ++nTokCount; + bStart = true; + } + } + } + + return nTokCount; + } + + + OUString QuotedTokenizedString::GetTokenSpecial(sal_Int32& nStartPos, sal_Unicode cTok, sal_Unicode cStrDel) const + { + const sal_Int32 nLen = m_sString.getLength(); + if ( nLen ) + { + bool bInString = (nStartPos < nLen) && (m_sString[nStartPos] == cStrDel); // are we WITHIN a (cStrDel delimited) String? + + // First character a String-Delimiter? + if (bInString ) + ++nStartPos; // skip this character! + if ( nStartPos >= nLen ) + return OUString(); + + OUStringBuffer sBuff( nLen - nStartPos + 1 ); + + // Search until end of string for the first not matching character + for( sal_Int32 i = nStartPos; i < nLen; ++i ) + { + const sal_Unicode cChar = m_sString[i]; + if (bInString) + { + // when now the String-Delimiter-character occurs ... + if ( cChar == cStrDel ) + { + if ((i+1 < nLen) && (m_sString[i+1] == cStrDel)) + { + // double String Delimiter-character + // no end of string, skip next character. + ++i; + sBuff.append(m_sString[i]); // character belongs to Result-String + } + else + { + //end of String + bInString = false; + } + } + else + { + sBuff.append(cChar); + } + } + else + { + // does the Token-sign match, then raise nTok + if ( cChar == cTok ) + { + // premature break of loop possible, because we found what we were looking for + nStartPos = i+1; + break; + } + else + { + sBuff.append(cChar); + } + } + } // for( sal_Int32 i = nStartPos; i < nLen; ++i ) + return sBuff.makeStringAndClear(); + } + return OUString(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Blob.cxx b/connectivity/source/drivers/firebird/Blob.cxx new file mode 100644 index 000000000..8ed9fc4a8 --- /dev/null +++ b/connectivity/source/drivers/firebird/Blob.cxx @@ -0,0 +1,388 @@ +/* -*- 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/. + */ + +#include "Blob.hxx" +#include "Util.hxx" + +#include <com/sun/star/io/BufferSizeExceededException.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <connectivity/CommonTools.hxx> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::connectivity::firebird; + +using namespace ::cppu; +using namespace ::osl; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +Blob::Blob(isc_db_handle* pDatabaseHandle, + isc_tr_handle* pTransactionHandle, + ISC_QUAD const & aBlobID): + Blob_BASE(m_aMutex), + m_pDatabaseHandle(pDatabaseHandle), + m_pTransactionHandle(pTransactionHandle), + m_blobID(aBlobID), +#if SAL_TYPES_SIZEOFPOINTER == 8 + m_blobHandle(0), +#else + m_blobHandle(nullptr), +#endif + m_bBlobOpened(false), + m_nBlobLength(0), + m_nMaxSegmentSize(0), + m_nBlobPosition(0) +{ +} + +void Blob::ensureBlobIsOpened() +{ + MutexGuard aGuard(m_aMutex); + + if (m_bBlobOpened) + return; + + ISC_STATUS aErr; + aErr = isc_open_blob2(m_statusVector, + m_pDatabaseHandle, + m_pTransactionHandle, + &m_blobHandle, + &m_blobID, + 0, + nullptr); + + if (aErr) + evaluateStatusVector(m_statusVector, "isc_open_blob2", *this); + + m_bBlobOpened = true; + m_nBlobPosition = 0; + + char aBlobItems[] = { + isc_info_blob_total_length, + isc_info_blob_max_segment + }; + + // Assuming a data (e.g. length of blob) is maximum 64 bit. + // That means we need 8 bytes for data + 2 for length of data + 1 for item + // identifier for each item. + char aResultBuffer[11 + 11]; + + aErr = isc_blob_info(m_statusVector, + &m_blobHandle, + sizeof(aBlobItems), + aBlobItems, + sizeof(aResultBuffer), + aResultBuffer); + + if (aErr) + evaluateStatusVector(m_statusVector, "isc_blob_info", *this); + + char* pIt = aResultBuffer; + while( *pIt != isc_info_end ) // info is in clusters + { + char item = *pIt++; + short aResultLength = static_cast<short>(isc_vax_integer(pIt, 2)); + + pIt += 2; + switch(item) + { + case isc_info_blob_total_length: + m_nBlobLength = isc_vax_integer(pIt, aResultLength); + break; + case isc_info_blob_max_segment: + m_nMaxSegmentSize = isc_vax_integer(pIt, aResultLength); + break; + default: + assert(false); + break; + } + pIt += aResultLength; + } +} + +sal_uInt16 Blob::getMaximumSegmentSize() +{ + ensureBlobIsOpened(); + + return m_nMaxSegmentSize; +} + +bool Blob::readOneSegment(uno::Sequence< sal_Int8 >& rDataOut) +{ + checkDisposed(Blob_BASE::rBHelper.bDisposed); + ensureBlobIsOpened(); + + sal_uInt16 nMaxSize = getMaximumSegmentSize(); + + if(rDataOut.getLength() < nMaxSize) + rDataOut.realloc(nMaxSize); + + sal_uInt16 nActualSize = 0; + ISC_STATUS aRet = isc_get_segment(m_statusVector, + &m_blobHandle, + &nActualSize, + nMaxSize, + reinterpret_cast<char*>(rDataOut.getArray()) ); + + if (aRet && aRet != isc_segstr_eof && IndicatesError(m_statusVector)) + { + OUString sError(StatusVectorToString(m_statusVector, "isc_get_segment")); + throw IOException(sError, *this); + } + m_nBlobPosition += nActualSize; + return aRet == isc_segstr_eof; // last segment read +} + + +void Blob::closeBlob() +{ + MutexGuard aGuard(m_aMutex); + + if (!m_bBlobOpened) + return; + + ISC_STATUS aErr; + aErr = isc_close_blob(m_statusVector, + &m_blobHandle); + if (aErr) + evaluateStatusVector(m_statusVector, "isc_close_blob", *this); + + m_bBlobOpened = false; +#if SAL_TYPES_SIZEOFPOINTER == 8 + m_blobHandle = 0; +#else + m_blobHandle = nullptr; +#endif +} + +void SAL_CALL Blob::disposing() +{ + try + { + closeBlob(); + } + catch (const SQLException &) + { + // we cannot throw any exceptions here... + TOOLS_WARN_EXCEPTION("connectivity.firebird", "isc_close_blob failed"); + assert(false); + } + Blob_BASE::disposing(); +} + +sal_Int64 SAL_CALL Blob::length() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(Blob_BASE::rBHelper.bDisposed); + ensureBlobIsOpened(); + + return m_nBlobLength; +} + +uno::Sequence< sal_Int8 > SAL_CALL Blob::getBytes(sal_Int64 nPosition, + sal_Int32 nBytes) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(Blob_BASE::rBHelper.bDisposed); + ensureBlobIsOpened(); + + if (nPosition > m_nBlobLength || nPosition < 1) + throw lang::IllegalArgumentException("nPosition out of range", *this, 0); + // We only have to read as many bytes as are available, i.e. nPosition+nBytes + // can legally be greater than the total length, hence we don't bother to check. + + if (nPosition -1 < m_nBlobPosition) + { + // Resets to the beginning (we can't seek these blobs) + closeBlob(); + ensureBlobIsOpened(); + } + + // nPosition is indexed from 1. + skipBytes(nPosition - m_nBlobPosition -1 ); + + // Don't bother preallocating: readBytes does the appropriate calculations + // and reallocates for us. + uno::Sequence< sal_Int8 > aBytes; + readBytes(aBytes, nBytes); + return aBytes; +} + +uno::Reference< XInputStream > SAL_CALL Blob::getBinaryStream() +{ + return this; +} + +sal_Int64 SAL_CALL Blob::position(const uno::Sequence< sal_Int8 >& /*rPattern*/, + sal_Int64 /*nStart*/) +{ + ::dbtools::throwFeatureNotImplementedSQLException("Blob::position", *this); + return 0; +} + +sal_Int64 SAL_CALL Blob::positionOfBlob(const uno::Reference< XBlob >& /*rPattern*/, + sal_Int64 /*aStart*/) +{ + ::dbtools::throwFeatureNotImplementedSQLException("Blob::positionOfBlob", *this); + return 0; +} + +// ---- XInputStream ---------------------------------------------------------- + +sal_Int32 SAL_CALL Blob::readBytes(uno::Sequence< sal_Int8 >& rDataOut, + sal_Int32 nBytes) +{ + MutexGuard aGuard(m_aMutex); + + try + { + checkDisposed(Blob_BASE::rBHelper.bDisposed); + ensureBlobIsOpened(); + } + catch (const NotConnectedException&) + { + throw; + } + catch (const BufferSizeExceededException&) + { + throw; + } + catch (const IOException&) + { + throw; + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception& e) + { + css::uno::Any a(cppu::getCaughtException()); + throw css::lang::WrappedTargetRuntimeException( + "wrapped Exception " + e.Message, + css::uno::Reference<css::uno::XInterface>(), a); + } + + // Ensure we have enough space for the amount of data we can actually read. + const sal_Int64 nBytesAvailable = m_nBlobLength - m_nBlobPosition; + const sal_Int32 nBytesToRead = std::min<sal_Int64>(nBytes, nBytesAvailable); + + if (rDataOut.getLength() < nBytesToRead) + rDataOut.realloc(nBytesToRead); + + sal_Int32 nTotalBytesRead = 0; + ISC_STATUS aErr; + while (nTotalBytesRead < nBytesToRead) + { + sal_uInt16 nBytesRead = 0; + sal_uInt64 nDataRemaining = nBytesToRead - nTotalBytesRead; + sal_uInt16 nReadSize = std::min<sal_uInt64>(nDataRemaining, SAL_MAX_UINT16); + aErr = isc_get_segment(m_statusVector, + &m_blobHandle, + &nBytesRead, + nReadSize, + reinterpret_cast<char*>(rDataOut.getArray()) + nTotalBytesRead); + if (aErr && IndicatesError(m_statusVector)) + { + OUString sError(StatusVectorToString(m_statusVector, "isc_get_segment")); + throw IOException(sError, *this); + } + nTotalBytesRead += nBytesRead; + m_nBlobPosition += nBytesRead; + } + + return nTotalBytesRead; +} + +sal_Int32 SAL_CALL Blob::readSomeBytes(uno::Sequence< sal_Int8 >& rDataOut, + sal_Int32 nMaximumBytes) +{ + // We don't have any way of verifying how many bytes are immediately available, + // hence we just pass through direct to readBytes + // (Spec: "reads the available number of bytes, at maximum nMaxBytesToRead.") + return readBytes(rDataOut, nMaximumBytes); +} + +void SAL_CALL Blob::skipBytes(sal_Int32 nBytesToSkip) +{ + // There is no way of directly skipping, hence we have to pretend to skip + // by reading & discarding the data. + uno::Sequence< sal_Int8 > aBytes; + readBytes(aBytes, nBytesToSkip); +} + +sal_Int32 SAL_CALL Blob::available() +{ + MutexGuard aGuard(m_aMutex); + + try + { + checkDisposed(Blob_BASE::rBHelper.bDisposed); + ensureBlobIsOpened(); + } + catch (const NotConnectedException&) + { + throw; + } + catch (const IOException&) + { + throw; + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception& e) + { + css::uno::Any a(cppu::getCaughtException()); + throw css::lang::WrappedTargetRuntimeException( + "wrapped Exception " + e.Message, + css::uno::Reference<css::uno::XInterface>(), a); + } + + return m_nBlobLength - m_nBlobPosition; +} + +void SAL_CALL Blob::closeInput() +{ + try + { + closeBlob(); + } + catch (const NotConnectedException&) + { + throw; + } + catch (const IOException&) + { + throw; + } + catch (const RuntimeException&) + { + throw; + } + catch (const Exception& e) + { + css::uno::Any a(cppu::getCaughtException()); + throw css::lang::WrappedTargetRuntimeException( + "wrapped Exception " + e.Message, + css::uno::Reference<css::uno::XInterface>(), a); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Blob.hxx b/connectivity/source/drivers/firebird/Blob.hxx new file mode 100644 index 000000000..0a3627de4 --- /dev/null +++ b/connectivity/source/drivers/firebird/Blob.hxx @@ -0,0 +1,103 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_BLOB_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_BLOB_HXX + +#include <ibase.h> + +#include <cppuhelper/compbase.hxx> + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/sdbc/XBlob.hpp> + +namespace connectivity +{ + namespace firebird + { + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XBlob, + css::io::XInputStream > + Blob_BASE; + + class Blob : + public Blob_BASE + { + protected: + ::osl::Mutex m_aMutex; + + isc_db_handle* m_pDatabaseHandle; + isc_tr_handle* m_pTransactionHandle; + // We store our own copy of the blob id as typically the statement + // manages its own blob id, and blobs are independent of a statement + // in firebird. + ISC_QUAD m_blobID; + isc_blob_handle m_blobHandle; + + bool m_bBlobOpened; + sal_Int64 m_nBlobLength; + sal_uInt16 m_nMaxSegmentSize; + sal_Int64 m_nBlobPosition; + + ISC_STATUS_ARRAY m_statusVector; + + /// @throws css::sdbc::SQLException + void ensureBlobIsOpened(); + /** + * Closes the blob and cleans up resources -- can be used to reset + * the blob if we e.g. want to read from the beginning again. + * + * @throws css::sdbc::SQLException + */ + void closeBlob(); + sal_uInt16 getMaximumSegmentSize(); + + public: + Blob(isc_db_handle* pDatabaseHandle, + isc_tr_handle* pTransactionHandle, + ISC_QUAD const & aBlobID); + + bool readOneSegment(css::uno::Sequence< sal_Int8 >& rDataOut); + + // ---- XBlob ---------------------------------------------------- + virtual sal_Int64 SAL_CALL + length() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL + getBytes(sal_Int64 aPosition, sal_Int32 aLength) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getBinaryStream() override; + virtual sal_Int64 SAL_CALL + position(const css::uno::Sequence< sal_Int8 >& rPattern, + sal_Int64 aStart) override; + virtual sal_Int64 SAL_CALL + positionOfBlob(const css::uno::Reference< css::sdbc::XBlob >& rPattern, + sal_Int64 aStart) override; + + // ---- XInputStream ---------------------------------------------- + virtual sal_Int32 SAL_CALL + readBytes(css::uno::Sequence< sal_Int8 >& rDataOut, + sal_Int32 nBytes) override; + virtual sal_Int32 SAL_CALL + readSomeBytes(css::uno::Sequence< sal_Int8 >& rDataOut, + sal_Int32 nMaximumBytes) override; + virtual void SAL_CALL + skipBytes(sal_Int32 nBytes) override; + virtual sal_Int32 SAL_CALL + available() override; + virtual void SAL_CALL + closeInput() override; + + // ---- OComponentHelper ------------------------------------------ + virtual void SAL_CALL disposing() override; + }; + } + +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_BLOB_HXX +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Catalog.cxx b/connectivity/source/drivers/firebird/Catalog.cxx new file mode 100644 index 000000000..f5969f31c --- /dev/null +++ b/connectivity/source/drivers/firebird/Catalog.cxx @@ -0,0 +1,95 @@ +/* -*- 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/. + */ + +#include "Catalog.hxx" +#include "Tables.hxx" +#include "Users.hxx" + +#include <com/sun/star/sdbc/XRow.hpp> + +using namespace ::connectivity::firebird; +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +Catalog::Catalog(const uno::Reference< XConnection >& rConnection): + OCatalog(rConnection), + m_xConnection(rConnection) +{ +} + +//----- OCatalog ------------------------------------------------------------- +void Catalog::refreshTables() +{ + Sequence< OUString > aTypes(2); + aTypes[0] = "TABLE"; + aTypes[1] = "VIEW"; + + uno::Reference< XResultSet > xTables = m_xMetaData->getTables(Any(), + "%", + "%", + aTypes); + + if (!xTables.is()) + return; + + ::std::vector< OUString> aTableNames; + + fillNames(xTables, aTableNames); + + if (!m_pTables) + m_pTables.reset( new Tables(m_xConnection->getMetaData(), + *this, + m_aMutex, + aTableNames) ); + else + m_pTables->reFill(aTableNames); + +} + +void Catalog::refreshViews() +{ + // TODO: implement me. + // Sets m_pViews (OCatalog) +} + +//----- IRefreshableGroups --------------------------------------------------- +void Catalog::refreshGroups() +{ + // TODO: implement me +} + +//----- IRefreshableUsers ---------------------------------------------------- +void Catalog::refreshUsers() +{ + OUString const sSql("SELECT DISTINCT RDB$USER FROM RDB$USER_PRIVILEGES"); + + Reference<XStatement> xStmt= m_xMetaData->getConnection()->createStatement(); + uno::Reference< XResultSet > xUsers = xStmt->executeQuery(sSql); + + if (!xUsers.is()) + return; + + ::std::vector< OUString> aUserNames; + + uno::Reference< XRow > xRow(xUsers,UNO_QUERY); + while (xUsers->next()) + { + aUserNames.push_back(xRow->getString(1)); + } + + if (!m_pUsers) + m_pUsers.reset( new Users(m_xConnection->getMetaData(), + *this, + m_aMutex, + aUserNames) ); + else + m_pUsers->reFill(aUserNames); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Catalog.hxx b/connectivity/source/drivers/firebird/Catalog.hxx new file mode 100644 index 000000000..b3c9ae4fe --- /dev/null +++ b/connectivity/source/drivers/firebird/Catalog.hxx @@ -0,0 +1,42 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CATALOG_HXX + +#include <sdbcx/VCatalog.hxx> + +namespace connectivity +{ + namespace firebird + { + class Catalog: public ::connectivity::sdbcx::OCatalog + { + css::uno::Reference< css::sdbc::XConnection > + m_xConnection; + + public: + explicit Catalog(const css::uno::Reference< css::sdbc::XConnection >& rConnection); + + // OCatalog + virtual void refreshTables() override; + virtual void refreshViews() override; + + // IRefreshableGroups + virtual void refreshGroups() override; + + // IRefreshableUsers + virtual void refreshUsers() override; + }; + } // namespace firebird +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Clob.cxx b/connectivity/source/drivers/firebird/Clob.cxx new file mode 100644 index 000000000..2038dfc11 --- /dev/null +++ b/connectivity/source/drivers/firebird/Clob.cxx @@ -0,0 +1,155 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <string_view> + +#include "Clob.hxx" +#include "Blob.hxx" + +#include <connectivity/CommonTools.hxx> +#include <connectivity/dbexception.hxx> + +using namespace ::connectivity::firebird; + +using namespace ::osl; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +Clob::Clob(isc_db_handle* pDatabaseHandle, + isc_tr_handle* pTransactionHandle, + ISC_QUAD const & aBlobID): + Clob_BASE(m_aMutex), + m_aBlob(new connectivity::firebird::Blob(pDatabaseHandle, pTransactionHandle, aBlobID)), + m_nCharCount(-1) +{ +} + +void SAL_CALL Clob::disposing() +{ + m_aBlob->dispose(); + m_aBlob.clear(); + Clob_BASE::disposing(); +} + +sal_Int64 SAL_CALL Clob::length() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(Clob_BASE::rBHelper.bDisposed); + + if( m_nCharCount >= 0 ) + return m_nCharCount; + m_nCharCount = 0; + + // Read each segment, and calculate it's size by interpreting it as a + // character stream. Assume that no characters are split by the segments. + bool bLastSegmRead = false; + do + { + uno::Sequence < sal_Int8 > aSegmentBytes; + bLastSegmRead = m_aBlob->readOneSegment( aSegmentBytes ); + OUString sSegment ( reinterpret_cast< char *>( aSegmentBytes.getArray() ), + aSegmentBytes.getLength(), + RTL_TEXTENCODING_UTF8 ); + + if( !bLastSegmRead) + m_nCharCount += sSegment.getLength(); + }while( !bLastSegmRead ); + + m_aBlob->closeInput(); // reset position + return m_nCharCount; +} + +OUString SAL_CALL Clob::getSubString(sal_Int64 nPosition, + sal_Int32 nLength) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(Clob_BASE::rBHelper.bDisposed); + // TODO do not reset position if it is not necessary + m_aBlob->closeInput(); // reset position + + OUStringBuffer sSegmentBuffer; + sal_Int64 nActPos = 1; + sal_Int32 nActLen = 0; + + // skip irrelevant parts + while( nActPos < nPosition ) + { + uno::Sequence < sal_Int8 > aSegmentBytes; + bool bLastRead = m_aBlob->readOneSegment( aSegmentBytes ); + if( bLastRead ) + throw lang::IllegalArgumentException("nPosition out of range", *this, 0); + + OUString sSegment ( reinterpret_cast< char *>( aSegmentBytes.getArray() ), + aSegmentBytes.getLength(), + RTL_TEXTENCODING_UTF8 ); + sal_Int32 nStrLen = sSegment.getLength(); + nActPos += nStrLen; + if( nActPos > nPosition ) + { + sal_Int32 nCharsToCopy = static_cast<sal_Int32>(nActPos - nPosition); + if( nCharsToCopy > nLength ) + nCharsToCopy = nLength; + // append relevant part of first segment + sSegmentBuffer.append( std::u16string_view(sSegment).substr(0, nCharsToCopy) ); + nActLen += sSegmentBuffer.getLength(); + } + } + + // read nLength characters + while( nActLen < nLength ) + { + uno::Sequence < sal_Int8 > aSegmentBytes; + bool bLastRead = m_aBlob->readOneSegment( aSegmentBytes ); + + OUString sSegment ( reinterpret_cast< char *>( aSegmentBytes.getArray() ), + aSegmentBytes.getLength(), + RTL_TEXTENCODING_UTF8 ); + sal_Int32 nStrLen = sSegment.getLength(); + if( nActLen + nStrLen > nLength ) + sSegmentBuffer.append(std::u16string_view(sSegment).substr(0, nLength - nActLen)); + else + sSegmentBuffer.append(sSegment); + nActLen += nStrLen; + + if( bLastRead && nActLen < nLength ) + throw lang::IllegalArgumentException("out of range", *this, 0); + } + + return sSegmentBuffer.makeStringAndClear(); +} + +uno::Reference< XInputStream > SAL_CALL Clob::getCharacterStream() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(Clob_BASE::rBHelper.bDisposed); + + return m_aBlob->getBinaryStream(); +} + +sal_Int64 SAL_CALL Clob::position(const OUString& /*rPattern*/, + sal_Int32 /*nStart*/) +{ + ::dbtools::throwFeatureNotImplementedSQLException("Clob::position", *this); + return 0; +} + +sal_Int64 SAL_CALL Clob::positionOfClob(const Reference <XClob >& /*rPattern*/, + sal_Int64 /*aStart*/) +{ + ::dbtools::throwFeatureNotImplementedSQLException("Blob::positionOfBlob", *this); + return 0; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Clob.hxx b/connectivity/source/drivers/firebird/Clob.hxx new file mode 100644 index 000000000..626b284d3 --- /dev/null +++ b/connectivity/source/drivers/firebird/Clob.hxx @@ -0,0 +1,69 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CLOB_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CLOB_HXX + +#include "Blob.hxx" + +#include <cppuhelper/compbase.hxx> + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/sdbc/XClob.hpp> +#include <rtl/ref.hxx> + +namespace connectivity +{ + namespace firebird + { + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XClob > + Clob_BASE; + + class Clob : + public Clob_BASE + { + protected: + ::osl::Mutex m_aMutex; + + /* + * In Firebird Clob (textual Blob) is a subtype of blob, + * hence we store the data in a Blob, and the Clob class is + * a wrapper around that. + */ + rtl::Reference<connectivity::firebird::Blob> m_aBlob; + + sal_Int64 m_nCharCount; + + public: + Clob(isc_db_handle* pDatabaseHandle, + isc_tr_handle* pTransactionHandle, + ISC_QUAD const & aBlobID); + + // ---- XClob ---------------------------------------------------- + virtual sal_Int64 SAL_CALL + length() override; + virtual OUString SAL_CALL + getSubString(sal_Int64 aPosition, sal_Int32 aLength) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getCharacterStream() override; + virtual sal_Int64 SAL_CALL + position(const OUString& rPattern, + sal_Int32 aStart) override; + virtual sal_Int64 SAL_CALL + positionOfClob(const ::css::uno::Reference< ::css::sdbc::XClob >& rPattern, + sal_Int64 aStart) override; + // ---- OComponentHelper ------------------------------------------ + virtual void SAL_CALL disposing() override; + }; + } + +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CLOB_HXX +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Column.cxx b/connectivity/source/drivers/firebird/Column.cxx new file mode 100644 index 000000000..aa8abf9bb --- /dev/null +++ b/connectivity/source/drivers/firebird/Column.cxx @@ -0,0 +1,51 @@ +/* -*- 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/. + */ + +#include "Column.hxx" + +#include <TConnection.hxx> + +using namespace connectivity; +using namespace connectivity::firebird; +using namespace connectivity::sdbcx; + +Column::Column() + : OColumn( true ) // case sensitive +{ + construct(); +} + +void Column::construct() +{ + m_sAutoIncrement = "GENERATED BY DEFAULT AS IDENTITY"; + registerProperty(OMetaConnection::getPropMap().getNameByIndex( + PROPERTY_ID_AUTOINCREMENTCREATION), + PROPERTY_ID_AUTOINCREMENTCREATION, + 0, + &m_sAutoIncrement, + cppu::UnoType<decltype(m_sAutoIncrement)>::get() + ); +} + +::cppu::IPropertyArrayHelper* Column::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & SAL_CALL Column::getInfoHelper() +{ + return *Column_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +css::uno::Sequence< OUString > SAL_CALL Column::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbc.Firebird" }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Column.hxx b/connectivity/source/drivers/firebird/Column.hxx new file mode 100644 index 000000000..b72203da8 --- /dev/null +++ b/connectivity/source/drivers/firebird/Column.hxx @@ -0,0 +1,36 @@ +/* -*- 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/. + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_HCOLUMN_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_HCOLUMN_HXX + +#include <connectivity/sdbcx/VColumn.hxx> + +namespace connectivity +{ + namespace firebird + { + class Column; + typedef ::comphelper::OIdPropertyArrayUsageHelper<Column> Column_PROP; + class Column : public sdbcx::OColumn, + public Column_PROP + { + OUString m_sAutoIncrement; + protected: + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + public: + Column(); + virtual void construct() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Columns.cxx b/connectivity/source/drivers/firebird/Columns.cxx new file mode 100644 index 000000000..293dac97d --- /dev/null +++ b/connectivity/source/drivers/firebird/Columns.cxx @@ -0,0 +1,41 @@ +/* -*- 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/. + */ + +#include "Columns.hxx" +#include "Column.hxx" + +using namespace ::connectivity; +using namespace ::connectivity::firebird; +using namespace ::connectivity::sdbcx; + +using namespace ::cppu; +using namespace ::osl; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +Columns::Columns(Table& rTable, + Mutex& rMutex, + const ::std::vector< OUString>& rVector): + OColumnsHelper(rTable, + true, // TODO: is this case sensitivity? + rMutex, + rVector, + /*bUseHardRef*/true) +{ + OColumnsHelper::setParent(&rTable); +} + +Reference< css::beans::XPropertySet > Columns::createDescriptor() +{ + return new Column; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Columns.hxx b/connectivity/source/drivers/firebird/Columns.hxx new file mode 100644 index 000000000..844d99ee0 --- /dev/null +++ b/connectivity/source/drivers/firebird/Columns.hxx @@ -0,0 +1,37 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_COLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_COLUMNS_HXX + +#include "Table.hxx" + +#include <connectivity/TColumnsHelper.hxx> + +namespace connectivity +{ + namespace firebird + { + class Columns: public ::connectivity::OColumnsHelper + { + protected: + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + public: + Columns(Table& rTable, + ::osl::Mutex& rMutex, + const ::std::vector< OUString> &_rVector); + }; + + } // namespace firebird +} // namespace connectivity + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_COLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Connection.cxx b/connectivity/source/drivers/firebird/Connection.cxx new file mode 100644 index 000000000..b5a3c4ce7 --- /dev/null +++ b/connectivity/source/drivers/firebird/Connection.cxx @@ -0,0 +1,959 @@ +/* -*- 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 "Blob.hxx" +#include "Catalog.hxx" +#include "Clob.hxx" +#include "Connection.hxx" +#include "DatabaseMetaData.hxx" +#include "Driver.hxx" +#include "PreparedStatement.hxx" +#include "Statement.hxx" +#include "Util.hxx" + +#include <stdexcept> + +#include <com/sun/star/document/XDocumentEventBroadcaster.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <com/sun/star/ucb/SimpleFileAccess.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess2.hpp> + +#include <connectivity/dbexception.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + +#include <comphelper/processfactory.hxx> +#include <comphelper/storagehelper.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <unotools/tempfile.hxx> +#include <unotools/localfilehelper.hxx> + +#include <rtl/strbuf.hxx> +#include <sal/log.hxx> + +using namespace connectivity::firebird; +using namespace connectivity; + +using namespace ::osl; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::uno; + +/** + * Location within the .odb that an embedded .fdb will be stored. + * Only relevant for embedded dbs. + */ +static const OUStringLiteral our_sFDBLocation( "firebird.fdb" ); +/** + * Older version of LO may store the database in a .fdb file + */ +static const OUStringLiteral our_sFBKLocation( "firebird.fbk" ); + +Connection::Connection() + : Connection_BASE(m_aMutex) + , m_sConnectionURL() + , m_sFirebirdURL() + , m_bIsEmbedded(false) + , m_bIsFile(false) + , m_bIsAutoCommit(true) + , m_bIsReadOnly(false) + , m_aTransactionIsolation(TransactionIsolation::REPEATABLE_READ) +#if SAL_TYPES_SIZEOFPOINTER == 8 + , m_aDBHandle(0) + , m_aTransactionHandle(0) +#else + , m_aDBHandle(nullptr) + , m_aTransactionHandle(nullptr) +#endif + , m_xCatalog(nullptr) + , m_xMetaData(nullptr) + , m_aStatements() +{ +} + +Connection::~Connection() +{ + if(!isClosed()) + close(); +} + +namespace { + +struct ConnectionGuard +{ + oslInterlockedCount& m_refCount; + explicit ConnectionGuard(oslInterlockedCount& refCount) + : m_refCount(refCount) + { + osl_atomic_increment(&m_refCount); + } + ~ConnectionGuard() + { + osl_atomic_decrement(&m_refCount); + } +}; + +} + +void Connection::construct(const OUString& url, const Sequence< PropertyValue >& info) +{ + ConnectionGuard aGuard(m_refCount); + + try + { + m_sConnectionURL = url; + + bool bIsNewDatabase = false; + // the database may be stored as an + // fdb file in older versions + bool bIsFdbStored = false; + if (url == "sdbc:embedded:firebird") + { + m_bIsEmbedded = true; + + const PropertyValue* pIter = info.getConstArray(); + const PropertyValue* pEnd = pIter + info.getLength(); + + for (;pIter != pEnd; ++pIter) + { + if ( pIter->Name == "Storage" ) + { + m_xEmbeddedStorage.set(pIter->Value,UNO_QUERY); + } + else if ( pIter->Name == "Document" ) + { + pIter->Value >>= m_xParentDocument; + } + } + + if ( !m_xEmbeddedStorage.is() ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + bIsNewDatabase = !m_xEmbeddedStorage->hasElements(); + + m_pDatabaseFileDir.reset(new ::utl::TempFile(nullptr, true)); + m_pDatabaseFileDir->EnableKillingFile(); + m_sFirebirdURL = m_pDatabaseFileDir->GetFileName() + "/firebird.fdb"; + m_sFBKPath = m_pDatabaseFileDir->GetFileName() + "/firebird.fbk"; + + SAL_INFO("connectivity.firebird", "Temporary .fdb location: " << m_sFirebirdURL); + + if (!bIsNewDatabase) + { + if (m_xEmbeddedStorage->hasByName(our_sFBKLocation) && + m_xEmbeddedStorage->isStreamElement(our_sFBKLocation)) + { + SAL_INFO("connectivity.firebird", "Extracting* .fbk from .odb" ); + loadDatabaseFile(our_sFBKLocation, m_sFBKPath); + } + else if(m_xEmbeddedStorage->hasByName(our_sFDBLocation) && + m_xEmbeddedStorage->isStreamElement(our_sFDBLocation)) + { + SAL_INFO("connectivity.firebird", "Found .fdb instead of .fbk"); + bIsFdbStored = true; + loadDatabaseFile(our_sFDBLocation, m_sFirebirdURL); + } + else + { + // There might be files which are not firebird databases. + // This is not a problem. + bIsNewDatabase = true; + } + } + // TODO: Get DB properties from XML + + } + // External file AND/OR remote connection + else if (url.startsWith("sdbc:firebird:")) + { + m_sFirebirdURL = url.copy(OUString("sdbc:firebird:").getLength()); + if (m_sFirebirdURL.startsWith("file://")) + { + m_bIsFile = true; + uno::Reference< ucb::XSimpleFileAccess > xFileAccess = + ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()); + if (!xFileAccess->exists(m_sFirebirdURL)) + bIsNewDatabase = true; + + m_sFirebirdURL = m_sFirebirdURL.copy(OUString("file://").getLength()); + } + } + + std::string dpbBuffer; + { + char userName[256] = ""; + char userPassword[256] = ""; + + dpbBuffer.push_back(isc_dpb_version1); + dpbBuffer.push_back(isc_dpb_sql_dialect); + dpbBuffer.push_back(1); // 1 byte long + dpbBuffer.push_back(FIREBIRD_SQL_DIALECT); + + // set UTF8 as default character set of the database + const char sCharset[] = "UTF8"; + dpbBuffer.push_back(isc_dpb_set_db_charset); + dpbBuffer.push_back(sizeof(sCharset) - 1); + dpbBuffer.append(sCharset); + // set UTF8 as default character set of the connection + dpbBuffer.push_back(isc_dpb_lc_ctype); + dpbBuffer.push_back(sizeof(sCharset) - 1); + dpbBuffer.append(sCharset); + + // Do any more dpbBuffer additions here + + if (m_bIsEmbedded || m_bIsFile) + { + strcpy(userName,"sysdba"); + strcpy(userPassword,"masterkey"); + } + else + { + // TODO: parse password from connection string as needed? + } + + if (strlen(userName)) + { + int nUsernameLength = strlen(userName); + dpbBuffer.push_back(isc_dpb_user_name); + dpbBuffer.push_back(nUsernameLength); + dpbBuffer.append(userName); + } + + if (strlen(userPassword)) + { + int nPasswordLength = strlen(userPassword); + dpbBuffer.push_back(isc_dpb_password); + dpbBuffer.push_back(nPasswordLength); + dpbBuffer.append(userPassword); + } + } + + ISC_STATUS_ARRAY status; /* status vector */ + ISC_STATUS aErr; + if (bIsNewDatabase) + { + aErr = isc_create_database(status, + m_sFirebirdURL.getLength(), + OUStringToOString(m_sFirebirdURL,RTL_TEXTENCODING_UTF8).getStr(), + &m_aDBHandle, + dpbBuffer.size(), + dpbBuffer.c_str(), + 0); + if (aErr) + { + evaluateStatusVector(status, "isc_create_database", *this); + } + } + else + { + if (m_bIsEmbedded && !bIsFdbStored) // We need to restore the .fbk first + { + runBackupService(isc_action_svc_restore); + } + + aErr = isc_attach_database(status, + m_sFirebirdURL.getLength(), + OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8).getStr(), + &m_aDBHandle, + dpbBuffer.size(), + dpbBuffer.c_str()); + if (aErr) + { + evaluateStatusVector(status, "isc_attach_database", *this); + } + } + + if (m_bIsEmbedded) // Add DocumentEventListener to save the .fdb as needed + { + // We need to attach as a document listener in order to be able to store + // the temporary db back into the .odb when saving + uno::Reference<XDocumentEventBroadcaster> xBroadcaster(m_xParentDocument, UNO_QUERY); + + if (xBroadcaster.is()) + xBroadcaster->addDocumentEventListener(this); + else + assert(false); + } + } + catch (const Exception&) + { + throw; + } + catch (const std::exception&) + { + throw; + } + catch (...) // const Firebird::Exception& firebird throws this, but doesn't install the fb_exception.h that declares it + + { + throw std::runtime_error("Generic Firebird::Exception"); + } +} + +void Connection::notifyDatabaseModified() +{ + if (m_xParentDocument.is()) // Only true in embedded mode + m_xParentDocument->setModified(true); +} + +//----- XServiceInfo --------------------------------------------------------- +IMPLEMENT_SERVICE_INFO(Connection, "com.sun.star.sdbc.drivers.firebird.Connection", + "com.sun.star.sdbc.Connection") + +Reference< XBlob> Connection::createBlob(ISC_QUAD const * pBlobId) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + Reference< XBlob > xReturn = new Blob(&m_aDBHandle, + &m_aTransactionHandle, + *pBlobId); + + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XClob> Connection::createClob(ISC_QUAD const * pBlobId) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + Reference< XClob > xReturn = new Clob(&m_aDBHandle, + &m_aTransactionHandle, + *pBlobId); + + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + + +//----- XConnection ---------------------------------------------------------- +Reference< XStatement > SAL_CALL Connection::createStatement( ) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + // the pre + if(m_aTypeInfo.empty()) + buildTypeInfo(); + + // create a statement + // the statement can only be executed once + Reference< XStatement > xReturn = new OStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL Connection::prepareStatement( + const OUString& _sSql) +{ + SAL_INFO("connectivity.firebird", "prepareStatement() " + "called with sql: " << _sSql); + MutexGuard aGuard(m_aMutex); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + if(m_aTypeInfo.empty()) + buildTypeInfo(); + + Reference< XPreparedStatement > xReturn = new OPreparedStatement(this, _sSql); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL Connection::prepareCall( + const OUString& _sSql ) +{ + SAL_INFO("connectivity.firebird", "prepareCall(). " + "_sSql: " << _sSql); + + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + // OUString sSqlStatement (transformPreparedStatement( _sSql )); + + // not implemented yet :-) a task to do + return nullptr; +} + +OUString SAL_CALL Connection::nativeSQL( const OUString& _sSql ) +{ + MutexGuard aGuard( m_aMutex ); + // We do not need to adapt the SQL for Firebird atm. + return _sSql; +} + +void SAL_CALL Connection::setAutoCommit( sal_Bool autoCommit ) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + m_bIsAutoCommit = autoCommit; + + if (m_aTransactionHandle) + { + setupTransaction(); + } +} + +sal_Bool SAL_CALL Connection::getAutoCommit() +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + return m_bIsAutoCommit; +} + +void Connection::setupTransaction() +{ + MutexGuard aGuard( m_aMutex ); + ISC_STATUS status_vector[20]; + + // TODO: is this sensible? If we have changed parameters then transaction + // is lost... + if (m_aTransactionHandle) + { + disposeStatements(); + isc_rollback_transaction(status_vector, &m_aTransactionHandle); + } + + char aTransactionIsolation = 0; + switch (m_aTransactionIsolation) + { + // TODO: confirm that these are correct. + case TransactionIsolation::READ_UNCOMMITTED: + aTransactionIsolation = isc_tpb_concurrency; + break; + case TransactionIsolation::READ_COMMITTED: + aTransactionIsolation = isc_tpb_read_committed; + break; + case TransactionIsolation::REPEATABLE_READ: + aTransactionIsolation = isc_tpb_consistency; + break; + case TransactionIsolation::SERIALIZABLE: + aTransactionIsolation = isc_tpb_consistency; + break; + default: + assert( false ); // We must have a valid TransactionIsolation. + } + + // You cannot pass an empty tpb parameter so we have to do some pointer + // arithmetic to avoid problems. (i.e. aTPB[x] = 0 is invalid) + char aTPB[5]; + char* pTPB = aTPB; + + *pTPB++ = isc_tpb_version3; + if (m_bIsAutoCommit) + *pTPB++ = isc_tpb_autocommit; + *pTPB++ = (!m_bIsReadOnly ? isc_tpb_write : isc_tpb_read); + *pTPB++ = aTransactionIsolation; + *pTPB++ = isc_tpb_wait; + + isc_start_transaction(status_vector, + &m_aTransactionHandle, + 1, + &m_aDBHandle, + pTPB - aTPB, // bytes used in TPB + aTPB); + + evaluateStatusVector(status_vector, + "isc_start_transaction", + *this); +} + +isc_tr_handle& Connection::getTransaction() +{ + MutexGuard aGuard( m_aMutex ); + if (!m_aTransactionHandle) + { + setupTransaction(); + } + return m_aTransactionHandle; +} + +void SAL_CALL Connection::commit() +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + ISC_STATUS status_vector[20]; + + if (!m_bIsAutoCommit && m_aTransactionHandle) + { + disposeStatements(); + isc_commit_transaction(status_vector, &m_aTransactionHandle); + evaluateStatusVector(status_vector, + "isc_commit_transaction", + *this); + } +} + +void Connection::loadDatabaseFile(const OUString& srcLocation, const OUString& tmpLocation) +{ + Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(srcLocation, + ElementModes::READ)); + + uno::Reference< ucb::XSimpleFileAccess2 > xFileAccess = + ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() ); + if ( !xFileAccess.is() ) + { + ::connectivity::SharedResources aResources; + // TODO FIXME: this does _not_ look like the right error message + const OUString sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + xFileAccess->writeFile(tmpLocation,xDBStream->getInputStream()); +} + +isc_svc_handle Connection::attachServiceManager() +{ + ISC_STATUS_ARRAY aStatusVector; +#if SAL_TYPES_SIZEOFPOINTER == 8 + isc_svc_handle aServiceHandle = 0; +#else + isc_svc_handle aServiceHandle = nullptr; +#endif + + char aSPBBuffer[256]; + char* pSPB = aSPBBuffer; + *pSPB++ = isc_spb_version; + *pSPB++ = isc_spb_current_version; + *pSPB++ = isc_spb_user_name; + OUString sUserName("SYSDBA"); + char aLength = static_cast<char>(sUserName.getLength()); + *pSPB++ = aLength; + strncpy(pSPB, + OUStringToOString(sUserName, + RTL_TEXTENCODING_UTF8).getStr(), + aLength); + pSPB += aLength; + // TODO: do we need ", isc_dpb_trusted_auth, 1, 1" -- probably not but ... + if (isc_service_attach(aStatusVector, + 0, // Denotes null-terminated string next + "service_mgr", + &aServiceHandle, + pSPB - aSPBBuffer, + aSPBBuffer)) + { + evaluateStatusVector(aStatusVector, + "isc_service_attach", + *this); + } + + return aServiceHandle; +} + +void Connection::detachServiceManager(isc_svc_handle aServiceHandle) +{ + ISC_STATUS_ARRAY aStatusVector; + if (isc_service_detach(aStatusVector, + &aServiceHandle)) + { + evaluateStatusVector(aStatusVector, + "isc_service_detach", + *this); + } +} + +void Connection::runBackupService(const short nAction) +{ + assert(nAction == isc_action_svc_backup + || nAction == isc_action_svc_restore); + + ISC_STATUS_ARRAY aStatusVector; + + // convert paths to 8-Bit strings + OString sFDBPath = OUStringToOString(m_sFirebirdURL, RTL_TEXTENCODING_UTF8); + OString sFBKPath = OUStringToOString(m_sFBKPath, RTL_TEXTENCODING_UTF8); + + + OStringBuffer aRequest; // byte array + + + aRequest.append(static_cast<char>(nAction)); + + aRequest.append(char(isc_spb_dbname)); // .fdb + sal_uInt16 nFDBLength = sFDBPath.getLength(); + aRequest.append(static_cast<char>(nFDBLength & 0xFF)); // least significant byte first + aRequest.append(static_cast<char>((nFDBLength >> 8) & 0xFF)); + aRequest.append(sFDBPath); + + aRequest.append(char(isc_spb_bkp_file)); // .fbk + sal_uInt16 nFBKLength = sFBKPath.getLength(); + aRequest.append(static_cast<char>(nFBKLength & 0xFF)); + aRequest.append(static_cast<char>((nFBKLength >> 8) & 0xFF)); + aRequest.append(sFBKPath); + + if (nAction == isc_action_svc_restore) + { + aRequest.append(char(isc_spb_options)); // 4-Byte bitmask + char sOptions[4]; + char * pOptions = sOptions; +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable: 4310) // cast truncates data +#endif + ADD_SPB_NUMERIC(pOptions, isc_spb_res_create); +#ifdef _WIN32 +#pragma warning(pop) +#endif + aRequest.append(sOptions, 4); + } + + isc_svc_handle aServiceHandle; + aServiceHandle = attachServiceManager(); + + if (isc_service_start(aStatusVector, + &aServiceHandle, + nullptr, + aRequest.getLength(), + aRequest.getStr())) + { + evaluateStatusVector(aStatusVector, "isc_service_start", *this); + } + + char aInfoSPB = isc_info_svc_line; + char aResults[256]; + + // query blocks until success or error + if(isc_service_query(aStatusVector, + &aServiceHandle, + nullptr, // Reserved null + 0,nullptr, // "send" spb -- size and spb -- not needed? + 1, + &aInfoSPB, + sizeof(aResults), + aResults)) + { + evaluateStatusVector(aStatusVector, "isc_service_query", *this); + } + + detachServiceManager(aServiceHandle); +} + + +void SAL_CALL Connection::rollback() +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + ISC_STATUS status_vector[20]; + + if (!m_bIsAutoCommit && m_aTransactionHandle) + { + isc_rollback_transaction(status_vector, &m_aTransactionHandle); + } +} + +sal_Bool SAL_CALL Connection::isClosed( ) +{ + MutexGuard aGuard( m_aMutex ); + + // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent) + return Connection_BASE::rBHelper.bDisposed; +} + +Reference< XDatabaseMetaData > SAL_CALL Connection::getMetaData( ) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + // here we have to create the class with biggest interface + // The answer is 42 :-) + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +void SAL_CALL Connection::setReadOnly(sal_Bool readOnly) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + m_bIsReadOnly = readOnly; + setupTransaction(); +} + +sal_Bool SAL_CALL Connection::isReadOnly() +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + return m_bIsReadOnly; +} + +void SAL_CALL Connection::setCatalog(const OUString& /*catalog*/) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setCatalog", *this); +} + +OUString SAL_CALL Connection::getCatalog() +{ + ::dbtools::throwFunctionNotSupportedSQLException("getCatalog", *this); + return OUString(); +} + +void SAL_CALL Connection::setTransactionIsolation( sal_Int32 level ) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + m_aTransactionIsolation = level; + setupTransaction(); +} + +sal_Int32 SAL_CALL Connection::getTransactionIsolation( ) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + return m_aTransactionIsolation; +} + +Reference< XNameAccess > SAL_CALL Connection::getTypeMap() +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::getTypeMap", *this ); + return nullptr; +} + +void SAL_CALL Connection::setTypeMap(const Reference< XNameAccess >&) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this ); +} + +//----- XCloseable ----------------------------------------------------------- +void SAL_CALL Connection::close( ) +{ + // we just dispose us + { + MutexGuard aGuard( m_aMutex ); + checkDisposed(Connection_BASE::rBHelper.bDisposed); + + } + dispose(); +} + +// XWarningsSupplier +Any SAL_CALL Connection::getWarnings( ) +{ + // when you collected some warnings -> return it + return Any(); +} + +void SAL_CALL Connection::clearWarnings( ) +{ + // you should clear your collected warnings here +} + +// XDocumentEventListener +void SAL_CALL Connection::documentEventOccured( const DocumentEvent& Event ) +{ + MutexGuard aGuard(m_aMutex); + + if (!m_bIsEmbedded) + return; + + if (!(Event.EventName == "OnSave" || Event.EventName == "OnSaveAs")) + return; + + commit(); // Commit and close transaction + if ( !(m_bIsEmbedded && m_xEmbeddedStorage.is()) ) + return; + + SAL_INFO("connectivity.firebird", "Writing .fbk from running db"); + try + { + runBackupService(isc_action_svc_backup); + } + catch (const SQLException& e) + { + auto a = cppu::getCaughtException(); + throw WrappedTargetRuntimeException(e.Message, e.Context, a); + } + + + Reference< XStream > xDBStream(m_xEmbeddedStorage->openStreamElement(our_sFBKLocation, + ElementModes::WRITE)); + + // TODO: verify the backup actually exists -- the backup service + // can fail without giving any sane error messages / telling us + // that it failed. + using namespace ::comphelper; + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + Reference< XInputStream > xInputStream; + if (!xContext.is()) + return; + + xInputStream = + OStorageHelper::GetInputStreamFromURL(m_sFBKPath, xContext); + if (xInputStream.is()) + OStorageHelper::CopyInputToOutput( xInputStream, + xDBStream->getOutputStream()); + + // remove old fdb file if exists + uno::Reference< ucb::XSimpleFileAccess > xFileAccess = + ucb::SimpleFileAccess::create(xContext); + if (xFileAccess->exists(m_sFirebirdURL)) + xFileAccess->kill(m_sFirebirdURL); +} +// XEventListener +void SAL_CALL Connection::disposing(const EventObject& /*rSource*/) +{ + MutexGuard aGuard( m_aMutex ); + + m_xEmbeddedStorage.clear(); +} + +void Connection::buildTypeInfo() +{ + MutexGuard aGuard( m_aMutex ); + + Reference< XResultSet> xRs = getMetaData ()->getTypeInfo (); + Reference< XRow> xRow(xRs,UNO_QUERY); + // Information for a single SQL type + + // Loop on the result set until we reach end of file + + while (xRs->next ()) + { + OTypeInfo aInfo; + aInfo.aTypeName = xRow->getString (1); + aInfo.nType = xRow->getShort (2); + aInfo.nPrecision = xRow->getInt (3); + // aLiteralPrefix = xRow->getString (4); + // aLiteralSuffix = xRow->getString (5); + // aCreateParams = xRow->getString (6); + // bNullable = xRow->getBoolean (7); + // bCaseSensitive = xRow->getBoolean (8); + // nSearchType = xRow->getShort (9); + // bUnsigned = xRow->getBoolean (10); + // bCurrency = xRow->getBoolean (11); + // bAutoIncrement = xRow->getBoolean (12); + aInfo.aLocalTypeName = xRow->getString (13); + // nMinimumScale = xRow->getShort (14); + aInfo.nMaximumScale = xRow->getShort (15); + // nNumPrecRadix = (sal_Int16)xRow->getInt(18); + + + // Now that we have the type info, save it + // in the Hashtable if we don't already have an + // entry for this SQL type. + + m_aTypeInfo.push_back(aInfo); + } + + SAL_INFO("connectivity.firebird", "buildTypeInfo(). " + "Type info built."); + + // Close the result set/statement. + + Reference< XCloseable> xClose(xRs,UNO_QUERY); + xClose->close(); + + SAL_INFO("connectivity.firebird", "buildTypeInfo(). " + "Closed."); +} + +void Connection::disposing() +{ + MutexGuard aGuard(m_aMutex); + + disposeStatements(); + + m_xMetaData = css::uno::WeakReference< css::sdbc::XDatabaseMetaData>(); + + ISC_STATUS_ARRAY status; /* status vector */ + if (m_aTransactionHandle) + { + // TODO: confirm whether we need to ask the user here. + isc_rollback_transaction(status, &m_aTransactionHandle); + } + + if (m_aDBHandle) + { + if (isc_detach_database(status, &m_aDBHandle)) + { + evaluateStatusVector(status, "isc_detach_database", *this); + } + } + // TODO: write to storage again? + + cppu::WeakComponentImplHelperBase::disposing(); + + if (m_pDatabaseFileDir) + { + ::utl::removeTree(m_pDatabaseFileDir->GetURL()); + m_pDatabaseFileDir.reset(); + } +} + +void Connection::disposeStatements() +{ + MutexGuard aGuard(m_aMutex); + for (auto const& statement : m_aStatements) + { + Reference< XComponent > xComp(statement.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + } + m_aStatements.clear(); +} + +uno::Reference< XTablesSupplier > Connection::createCatalog() +{ + MutexGuard aGuard(m_aMutex); + + // m_xCatalog is a weak reference. Reuse it if it still exists. + Reference< XTablesSupplier > xCatalog = m_xCatalog; + if (xCatalog.is()) + { + return xCatalog; + } + else + { + xCatalog = new Catalog(this); + m_xCatalog = xCatalog; + return m_xCatalog; + } + +} + + diff --git a/connectivity/source/drivers/firebird/Connection.hxx b/connectivity/source/drivers/firebird/Connection.hxx new file mode 100644 index 000000000..7365aa06a --- /dev/null +++ b/connectivity/source/drivers/firebird/Connection.hxx @@ -0,0 +1,246 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CONNECTION_HXX + +#include <ibase.h> + +#include <connectivity/CommonTools.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/weakref.hxx> +#include <memory> +#include <OTypeInfo.hxx> +#include <unotools/tempfile.hxx> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/document/DocumentEvent.hpp> +#include <com/sun/star/document/XDocumentEventListener.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/XBlob.hpp> +#include <com/sun/star/sdbc/XClob.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/util/XModifiable.hpp> + +namespace connectivity +{ + namespace firebird + { + + typedef ::cppu::WeakComponentImplHelper< css::document::XDocumentEventListener, + css::lang::XServiceInfo, + css::sdbc::XConnection, + css::sdbc::XWarningsSupplier + > Connection_BASE; + + class OStatementCommonBase; + class FirebirdDriver; + class ODatabaseMetaData; + + + typedef std::vector< ::connectivity::OTypeInfo> TTypeInfoVector; + typedef std::vector< css::uno::WeakReferenceHelper > OWeakRefArray; + + class Connection final : public Connection_BASE + { + ::osl::Mutex m_aMutex; + + TTypeInfoVector m_aTypeInfo; // vector containing an entry + // for each row returned by + // DatabaseMetaData.getTypeInfo. + + /** The URL passed to us when opening, i.e. of the form sdbc:* */ + OUString m_sConnectionURL; + /** + * The URL passed to firebird, i.e. either a local file (for a + * temporary .fdb extracted from a .odb or a normal local file) or + * a remote url. + */ + OUString m_sFirebirdURL; + + /* EMBEDDED MODE DATA */ + /** Denotes that we have a database stored within a .odb file. */ + bool m_bIsEmbedded; + + /** + * Handle for the parent DatabaseDocument. We need to notify this + * whenever any data is written to our temporary database so that + * the user is able to save this back to the .odb file. + * + * Note that this is ONLY set in embedded mode. + */ + css::uno::Reference< css::util::XModifiable > + m_xParentDocument; + + /** + * Handle for the folder within the .odb where we store our .fbk + * (Only used if m_bIsEmbedded is true). + */ + css::uno::Reference< css::embed::XStorage > + m_xEmbeddedStorage; + /** + * The temporary folder where we extract the .fbk from a .odb, + * and also store the temporary .fdb + * It is only valid if m_bIsEmbedded is true. + * + * The extracted .fbk is written in firebird.fbk, the temporary + * .fdb is stored as firebird.fdb. + */ + std::unique_ptr< ::utl::TempFile > m_pDatabaseFileDir; + /** + * Path for our extracted .fbk file. + * + * (The temporary .fdb is our m_sFirebirdURL.) + */ + OUString m_sFBKPath; + + void loadDatabaseFile(const OUString& pSrcLocation, const OUString& pTmpLocation); + + /** + * Run the backup service, use nAction = + * isc_action_svc_backup to backup, nAction = isc_action_svc_restore + * to restore. + */ + void runBackupService(const short nAction); + + isc_svc_handle attachServiceManager(); + + void detachServiceManager(isc_svc_handle pServiceHandle); + + /** We are using an external (local) file */ + bool m_bIsFile; + + /* CONNECTION PROPERTIES */ + bool m_bIsAutoCommit; + bool m_bIsReadOnly; + sal_Int32 m_aTransactionIsolation; + + isc_db_handle m_aDBHandle; + isc_tr_handle m_aTransactionHandle; + + css::uno::WeakReference< css::sdbcx::XTablesSupplier> + m_xCatalog; + css::uno::WeakReference< css::sdbc::XDatabaseMetaData > + m_xMetaData; + /** Statements owned by this connection. */ + OWeakRefArray m_aStatements; + + /// @throws css::sdbc::SQLException + void buildTypeInfo(); + + /** + * Creates a new transaction with the desired parameters, if + * necessary discarding an existing transaction. This has to be done + * anytime we change the transaction isolation, or autocommitting. + * + * @throws css::sdbc::SQLException + */ + void setupTransaction(); + void disposeStatements(); + + public: + explicit Connection(); + virtual ~Connection() override; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void construct( const OUString& url, + const css::uno::Sequence< css::beans::PropertyValue >& info); + + const OUString& getConnectionURL() const {return m_sConnectionURL;} + bool isEmbedded() const {return m_bIsEmbedded;} + isc_db_handle& getDBHandle() {return m_aDBHandle;} + /// @throws css::sdbc::SQLException + isc_tr_handle& getTransaction(); + + /** + * Must be called anytime the underlying database is likely to have + * changed. + * + * This is used to notify the database document of any changes, so + * that the user is informed of any pending changes needing to be + * saved. + */ + void notifyDatabaseModified(); + + /** + * Create a new Blob tied to this connection. Blobs are tied to a + * transaction and not to a statement, hence the connection should + * deal with their management. + * + * @throws css::sdbc::SQLException + * @throws css::uno::RuntimeException + */ + css::uno::Reference< css::sdbc::XBlob> + createBlob(ISC_QUAD const * pBlobID); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Reference< css::sdbc::XClob> + createClob(ISC_QUAD const * pBlobID); + + /** + * Create and/or connect to the sdbcx Catalog. This is completely + * unrelated to the SQL "Catalog". + */ + css::uno::Reference< css::sdbcx::XTablesSupplier > + createCatalog(); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XDocumentEventListener + virtual void SAL_CALL documentEventOccured( const css::document::DocumentEvent& Event ) override; + // css.lang.XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_CONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx new file mode 100644 index 000000000..fdcfd1d64 --- /dev/null +++ b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx @@ -0,0 +1,1810 @@ +/* -*- 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 "DatabaseMetaData.hxx" +#include "Util.hxx" + +#include <ibase.h> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <FDatabaseMetaDataResultSet.hxx> + +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/IndexType.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbc/Deferrability.hpp> + +using namespace connectivity::firebird; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +ODatabaseMetaData::ODatabaseMetaData(Connection* _pCon) +: m_pConnection(_pCon) +{ + SAL_WARN_IF(!m_pConnection.is(), "connectivity.firebird", + "ODatabaseMetaData::ODatabaseMetaData: No connection set!"); +} + +ODatabaseMetaData::~ODatabaseMetaData() +{ +} + +//----- Catalog Info -- UNSUPPORTED ------------------------------------------- +OUString SAL_CALL ODatabaseMetaData::getCatalogSeparator() +{ + return OUString(); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength() +{ + return -1; +} + +OUString SAL_CALL ODatabaseMetaData::getCatalogTerm() +{ + return OUString(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::isCatalogAtStart() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInTableDefinitions() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInDataManipulation( ) +{ + return false; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCatalogs() +{ + OSL_FAIL("Not implemented yet!"); + // TODO implement + return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eCatalogs); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions() +{ + return false; +} + +//----- Schema Info -- UNSUPPORTED -------------------------------------------- +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInDataManipulation() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInTableDefinitions() +{ + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength() +{ + return -1; +} + +OUString SAL_CALL ODatabaseMetaData::getSchemaTerm() +{ + return OUString(); +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSchemas() +{ + OSL_FAIL("Not implemented yet!"); + // TODO implement + return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eSchemas); +} + +//----- Max Sizes/Lengths ----------------------------------------------------- +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength() +{ + return 32767; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize() +{ + return 32767; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength() +{ + return 32767; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength() +{ + return 31; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex() +{ + // TODO: No idea. + // See: http://www.firebirdsql.org/en/firebird-technical-specifications/ + return 16; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength() +{ + return 32; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections() +{ + return 100; // Arbitrary +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable() +{ + // May however be smaller. + // See: http://www.firebirdsql.org/en/firebird-technical-specifications/ + return 32767; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength() +{ + return 32767; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength() +{ + return 31; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTablesInSelect( ) +{ + return 0; // 0 means no limit +} + + +sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + return false; +} + +// ---- Identifiers ----------------------------------------------------------- +// Only quoted identifiers are case sensitive, unquoted are case insensitive +OUString SAL_CALL ODatabaseMetaData::getIdentifierQuoteString() +{ + OUString aVal('"'); + return aVal; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseQuotedIdentifiers( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseQuotedIdentifiers() +{ + // TODO: confirm this -- the documentation is highly ambiguous + // However it seems this should be true as quoted identifiers ARE + // stored mixed case. + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers() +{ + return false; +} + +// ---- Unquoted Identifiers ------------------------------------------------- +// All unquoted identifiers are stored upper case. +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers() +{ + return true; +} + +// ---- SQL Feature Support --------------------------------------------------- +sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithAddColumn() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithDropColumn() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable() +{ + // TODO: true if embedded, but unsure about remote server + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert(sal_Int32, + sal_Int32) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames() +{ + return true; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( ) +{ + return 0; // 0 means no limit +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( ) +{ + return true; +} + +OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + return false; +} +// ---- Data definition stuff ------------------------------------------------- +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData:: + supportsDataDefinitionAndDataManipulationTransactions() +{ + return false; +} +//----- Transaction Support -------------------------------------------------- +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions() +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( + sal_Int32 aLevel) +{ + return aLevel == TransactionIsolation::READ_UNCOMMITTED + || aLevel == TransactionIsolation::READ_COMMITTED + || aLevel == TransactionIsolation::REPEATABLE_READ + || aLevel == TransactionIsolation::SERIALIZABLE; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation() +{ + return TransactionIsolation::REPEATABLE_READ; +} + + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + return true; // should be supported at least +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + return true; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatements( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( ) +{ + return 31; // TODO: confirm +} + +sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( ) +{ + return m_pConnection->isReadOnly(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( ) +{ + return m_pConnection->isEmbedded(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + // Unsure + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( ) +{ + // Unsure + return false; +} + + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + return false; +} + +OUString SAL_CALL ODatabaseMetaData::getURL() +{ + return m_pConnection->getConnectionURL(); +} + +OUString SAL_CALL ODatabaseMetaData::getUserName( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getDriverName( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getDriverVersion() +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( ) +{ + uno::Reference< XStatement > xSelect = m_pConnection->createStatement(); + + uno::Reference< XResultSet > xRs = xSelect->executeQuery("SELECT rdb$get_context('SYSTEM', 'ENGINE_VERSION') as version from rdb$database"); + (void)xRs->next(); // first and only row + uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW ); + return xRow->getString(1); +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( ) +{ + return "Firebird (engine12)"; +} + +OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( ) +{ + return OUString(); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( ) +{ + return 0; +} + +OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getStringFunctions( ) +{ + return "ASCII_CHAR,ASCII_VAL,BIT_LENGTH,CHAR_LENGTH,CHAR_TO_UUID,CHARACTER_LENGTH," + "GEN_UUID,HASH,LEFT,LOWER,LPAD,OCTET_LENGTH,OVERLAY,POSITION,REPLACE,REVERSE," + "RIGHT,RPAD,SUBSTRING,TRIM,UPPER,UUID_TO_CHAR"; +} + +OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( ) +{ + return "CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,DATEADD, DATEDIFF," + "EXTRACT,'NOW','TODAY','TOMORROW','YESTERDAY'"; +} + +OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( ) +{ + return "ABS,ACOS,ASIN,ATAN,ATAN2,BIN_AND,BIN_NOT,BIN_OR,BIN_SHL," + "BIN_SHR,BIN_XOR,CEIL,CEILING,COS,COSH,COT,EXP,FLOOR,LN," + "LOG,LOG10,MOD,PI,POWER,RAND,ROUND,SIGN,SIN,SINH,SQRT,TAN,TANH,TRUNC"; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( ) +{ + return 31; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType(sal_Int32 setType) +{ + switch (setType) + { + case ResultSetType::FORWARD_ONLY: + return true; + default: + return false; + } +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( + sal_Int32 aResultSetType, + sal_Int32 aConcurrency) +{ + if (aResultSetType == ResultSetType::FORWARD_ONLY + && aConcurrency == ResultSetConcurrency::READ_ONLY) + return true; + else + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates() +{ + // No batch support in firebird + return false; +} + +uno::Reference< XConnection > SAL_CALL ODatabaseMetaData::getConnection() +{ + return uno::Reference<XConnection>(m_pConnection.get()); +} + +// here follow all methods which return a resultset +// the first methods is an example implementation how to use this resultset +// of course you could implement it on your and you should do this because +// the general way is more memory expensive + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( ) +{ + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes); + uno::Reference< XResultSet > xResultSet = pResultSet; + + ODatabaseMetaDataResultSet::ORows aResults; + ODatabaseMetaDataResultSet::ORow aRow(2); + + aRow[0] = new ORowSetValueDecorator(); // unused + + // TODO Put these statics to one place + // like postgreSQL's Statics class. + + aRow[1] = new ORowSetValueDecorator(OUString("TABLE")); + aResults.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("VIEW")); + aResults.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("SYSTEM TABLE")); + aResults.push_back(aRow); + + pResultSet->setRows(aResults); + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTypeInfo() +{ + SAL_INFO("connectivity.firebird", "getTypeInfo()"); + + // this returns an empty resultset where the column-names are already set + // in special the metadata of the resultset already returns the right columns + ODatabaseMetaDataResultSet* pResultSet = + new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo); + uno::Reference< XResultSet > xResultSet = pResultSet; + static ODatabaseMetaDataResultSet::ORows aResults = []() + { + ODatabaseMetaDataResultSet::ORows tmp; + ODatabaseMetaDataResultSet::ORow aRow(19); + + // Common data + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); // Literal quote marks + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); // Literal quote marks + aRow[7] = new ORowSetValueDecorator(true); // Nullable + aRow[8] = new ORowSetValueDecorator(true); // Case sensitive + aRow[10] = new ORowSetValueDecorator(false); // Is unsigned + // FIXED_PREC_SCALE: docs state "can it be a money value? " however + // in reality this causes Base to treat all numbers as money formatted + // by default which is wrong (and formatting as money value is still + // possible for all values). + aRow[11] = new ORowSetValueDecorator(false); + // Localised Type Name -- TODO: implement (but can be null): + aRow[13] = new ORowSetValueDecorator(); + aRow[16] = new ORowSetValueDecorator(); // Unused + aRow[17] = new ORowSetValueDecorator(); // Unused + aRow[18] = new ORowSetValueDecorator(sal_Int16(10));// Radix + + // Char + aRow[1] = new ORowSetValueDecorator(OUString("CHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::CHAR); + aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::FULL)); // Searchable + aRow[12] = new ORowSetValueDecorator(false); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + + // Varchar + aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::VARCHAR); + aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::FULL)); // Searchable + aRow[12] = new ORowSetValueDecorator(false); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + + // Binary (CHAR); we use the Firebird synonym CHARACTER + // to fool LO into seeing it as different types. + // It is distinguished from Text type by its character set OCTETS; + // that will be added by Tables::createStandardColumnPart + aRow[1] = new ORowSetValueDecorator(OUString("CHARACTER")); + aRow[2] = new ORowSetValueDecorator(DataType::BINARY); + aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::NONE)); // Searchable + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + + // Varbinary (VARCHAR) + aRow[1] = new ORowSetValueDecorator(OUString("CHARACTER VARYING")); + aRow[2] = new ORowSetValueDecorator(DataType::VARBINARY); + aRow[3] = new ORowSetValueDecorator(sal_Int16(32765)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(OUString("length")); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::NONE)); // Searchable + + // Clob (SQL_BLOB) + aRow[1] = new ORowSetValueDecorator(OUString("BLOB SUB_TYPE TEXT")); // BLOB, with subtype 1 + aRow[2] = new ORowSetValueDecorator(DataType::CLOB); + aRow[3] = new ORowSetValueDecorator(sal_Int32(2147483647)); // Precision = max length + aRow[6] = new ORowSetValueDecorator(); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::FULL)); // Searchable + aRow[12] = new ORowSetValueDecorator(false); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + + // Longvarbinary (SQL_BLOB) + // Distinguished from simple blob with a user-defined subtype. + aRow[1] = new ORowSetValueDecorator(OUString("BLOB SUB_TYPE " + OUString::number(static_cast<short>(BlobSubtype::Image))) ); // BLOB, with subtype 0 + aRow[2] = new ORowSetValueDecorator(DataType::LONGVARBINARY); + tmp.push_back(aRow); + + // Integer Types common + { + aRow[6] = new ORowSetValueDecorator(); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::FULL)); // Searchable + aRow[12] = new ORowSetValueDecorator(true); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + } + // Smallint (SQL_SHORT) + aRow[1] = new ORowSetValueDecorator(OUString("SMALLINT")); + aRow[2] = new ORowSetValueDecorator(DataType::SMALLINT); + aRow[3] = new ORowSetValueDecorator(sal_Int16(5)); // Prevision + tmp.push_back(aRow); + // Integer (SQL_LONG) + aRow[1] = new ORowSetValueDecorator(OUString("INTEGER")); + aRow[2] = new ORowSetValueDecorator(DataType::INTEGER); + aRow[3] = new ORowSetValueDecorator(sal_Int16(10)); // Precision + tmp.push_back(aRow); + // Bigint (SQL_INT64) + aRow[1] = new ORowSetValueDecorator(OUString("BIGINT")); + aRow[2] = new ORowSetValueDecorator(DataType::BIGINT); + aRow[3] = new ORowSetValueDecorator(sal_Int16(20)); // Precision + tmp.push_back(aRow); + + // Decimal Types common + { + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::FULL)); // Searchable + aRow[12] = new ORowSetValueDecorator(true); // Autoincrement + } + + aRow[6] = new ORowSetValueDecorator(OUString("PRECISION,SCALE")); // Create params + // Numeric + aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC")); + aRow[2] = new ORowSetValueDecorator(DataType::NUMERIC); + aRow[3] = new ORowSetValueDecorator(sal_Int16(18)); // Precision + aRow[14] = new ORowSetValueDecorator(sal_Int16(0)); // Minimum scale + aRow[15] = new ORowSetValueDecorator(sal_Int16(18)); // Max scale + tmp.push_back(aRow); + // Decimal + aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL")); + aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL); + aRow[3] = new ORowSetValueDecorator(sal_Int16(18)); // Precision + aRow[14] = new ORowSetValueDecorator(sal_Int16(0)); // Minimum scale + aRow[15] = new ORowSetValueDecorator(sal_Int16(18)); // Max scale + tmp.push_back(aRow); + + aRow[6] = new ORowSetValueDecorator(); // Create Params + // Float (SQL_FLOAT) + aRow[1] = new ORowSetValueDecorator(OUString("FLOAT")); + aRow[2] = new ORowSetValueDecorator(DataType::FLOAT); + aRow[3] = new ORowSetValueDecorator(sal_Int16(7)); // Precision + aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale + aRow[15] = new ORowSetValueDecorator(sal_Int16(7)); // Max scale + tmp.push_back(aRow); + // Double (SQL_DOUBLE) + aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE PRECISION")); + aRow[2] = new ORowSetValueDecorator(DataType::DOUBLE); + aRow[3] = new ORowSetValueDecorator(sal_Int16(15)); // Precision + aRow[14] = new ORowSetValueDecorator(sal_Int16(1)); // Minimum scale + aRow[15] = new ORowSetValueDecorator(sal_Int16(15)); // Max scale + tmp.push_back(aRow); + + // TODO: no idea whether D_FLOAT corresponds to an sql type + + // SQL_TIMESTAMP + aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP")); + aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP); + aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::FULL)); // Searchable + aRow[12] = new ORowSetValueDecorator(false); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + + // SQL_TYPE_TIME + aRow[1] = new ORowSetValueDecorator(OUString("TIME")); + aRow[2] = new ORowSetValueDecorator(DataType::TIME); + aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::FULL)); // Searchable + aRow[12] = new ORowSetValueDecorator(false); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + + // SQL_TYPE_DATE + aRow[1] = new ORowSetValueDecorator(OUString("DATE")); + aRow[2] = new ORowSetValueDecorator(DataType::DATE); + aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::FULL)); // Searchable + aRow[12] = new ORowSetValueDecorator(false); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + + // SQL_BLOB + aRow[1] = new ORowSetValueDecorator(OUString("BLOB SUB_TYPE BINARY")); + aRow[2] = new ORowSetValueDecorator(DataType::BLOB); + aRow[3] = new ORowSetValueDecorator(sal_Int32(0)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::NONE)); // Searchable + aRow[12] = new ORowSetValueDecorator(false); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + + // SQL_BOOLEAN + aRow[1] = new ORowSetValueDecorator(OUString("BOOLEAN")); + aRow[2] = new ORowSetValueDecorator(DataType::BOOLEAN); + aRow[3] = new ORowSetValueDecorator(sal_Int32(1)); // Prevision = max length + aRow[6] = new ORowSetValueDecorator(); // Create Params + aRow[9] = new ORowSetValueDecorator( + sal_Int16(ColumnSearch::BASIC)); // Searchable + aRow[12] = new ORowSetValueDecorator(false); // Autoincrement + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); // Minimum scale + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); // Max scale + tmp.push_back(aRow); + return tmp; + }(); + pResultSet->setRows(aResults); + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumnPrivileges( + const Any& /*aCatalog*/, + const OUString& /*sSchema*/, + const OUString& sTable, + const OUString& sColumnNamePattern) +{ + SAL_INFO("connectivity.firebird", "getColumnPrivileges() with " + "Table: " << sTable + << " & ColumnNamePattern: " << sColumnNamePattern); + + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eColumnPrivileges); + uno::Reference< XResultSet > xResultSet = pResultSet; + uno::Reference< XStatement > statement = m_pConnection->createStatement(); + + static const char wld[] = "%"; + OUStringBuffer queryBuf( + "SELECT " + "priv.RDB$RELATION_NAME, " // 1 Table name + "priv.RDB$GRANTOR," // 2 + "priv.RDB$USER, " // 3 Grantee + "priv.RDB$PRIVILEGE, " // 4 + "priv.RDB$GRANT_OPTION, " // 5 is Grantable + "priv.RDB$FIELD_NAME " // 6 Column name + "FROM RDB$USER_PRIVILEGES priv "); + + { + OUString sAppend = "WHERE priv.RDB$RELATION_NAME = '%' "; + queryBuf.append(sAppend.replaceAll("%", sTable)); + } + if (!sColumnNamePattern.isEmpty()) + { + OUString sAppend; + if (sColumnNamePattern.match(wld)) + sAppend = "AND priv.RDB$FIELD_NAME LIKE '%' "; + else + sAppend = "AND priv.RDB$FIELD_NAME = '%' "; + + queryBuf.append(sAppend.replaceAll(wld, sColumnNamePattern)); + } + + queryBuf.append(" ORDER BY priv.RDB$FIELD, " + "priv.RDB$PRIVILEGE"); + + OUString query = queryBuf.makeStringAndClear(); + + uno::Reference< XResultSet > rs = statement->executeQuery(query.getStr()); + uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + ODatabaseMetaDataResultSet::ORows aResults; + + ODatabaseMetaDataResultSet::ORow aCurrentRow(9); + aCurrentRow[0] = new ORowSetValueDecorator(); // Unused + aCurrentRow[1] = new ORowSetValueDecorator(); // 1. TABLE_CAT Unsupported + aCurrentRow[2] = new ORowSetValueDecorator(); // 1. TABLE_SCHEM Unsupported + + while( rs->next() ) + { + // 3. TABLE_NAME + aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1))); + // 4. COLUMN_NAME + aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(6))); + aCurrentRow[5] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); // 5. GRANTOR + aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // 6. GRANTEE + aCurrentRow[7] = new ORowSetValueDecorator(xRow->getString(4)); // 7. Privilege + aCurrentRow[8] = new ORowSetValueDecorator( ( xRow->getShort(5) == 1 ) ? + OUString("YES") : OUString("NO")); // 8. Grantable + + aResults.push_back(aCurrentRow); + } + + pResultSet->setRows( aResults ); + + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( + const Any& /*catalog*/, + const OUString& /*schemaPattern*/, + const OUString& tableNamePattern, + const OUString& columnNamePattern) +{ + SAL_INFO("connectivity.firebird", "getColumns() with " + "TableNamePattern: " << tableNamePattern << + " & ColumnNamePattern: " << columnNamePattern); + + OUStringBuffer queryBuf("SELECT " + "relfields.RDB$RELATION_NAME, " // 1 + "relfields.RDB$FIELD_NAME, " // 2 + "relfields.RDB$DESCRIPTION," // 3 + "relfields.RDB$DEFAULT_VALUE, " // 4 + "relfields.RDB$FIELD_POSITION, "// 5 + "fields.RDB$FIELD_TYPE, " // 6 + "fields.RDB$FIELD_SUB_TYPE, " // 7 + "fields.RDB$FIELD_LENGTH, " // 8 + "fields.RDB$FIELD_PRECISION, " // 9 + "fields.RDB$FIELD_SCALE, " // 10 + // Specifically use relfields null flag -- the one in fields is used + // for domains, whether a specific field is nullable is set in relfields, + // this is also the one we manually fiddle when changing NULL/NOT NULL + // (see Table.cxx) + "relfields.RDB$NULL_FLAG, " // 11 + "fields.RDB$CHARACTER_LENGTH, " // 12 + "charset.RDB$CHARACTER_SET_NAME " // 13 + "FROM RDB$RELATION_FIELDS relfields " + "JOIN RDB$FIELDS fields " + "on (fields.RDB$FIELD_NAME = relfields.RDB$FIELD_SOURCE) " + "LEFT JOIN RDB$CHARACTER_SETS charset " + "on (fields.RDB$CHARACTER_SET_ID = charset.RDB$CHARACTER_SET_ID) " + "WHERE (1 = 1) "); + + if (!tableNamePattern.isEmpty()) + { + OUString sAppend; + if (tableNamePattern.match("%")) + sAppend = "AND relfields.RDB$RELATION_NAME LIKE '%' "; + else + sAppend = "AND relfields.RDB$RELATION_NAME = '%' "; + + queryBuf.append(sAppend.replaceAll("%", tableNamePattern)); + } + + if (!columnNamePattern.isEmpty()) + { + OUString sAppend; + if (columnNamePattern.match("%")) + sAppend = "AND relfields.RDB$FIELD_NAME LIKE '%' "; + else + sAppend = "AND relfields.RDB$FIELD_NAME = '%' "; + + queryBuf.append(sAppend.replaceAll("%", columnNamePattern)); + } + + OUString query = queryBuf.makeStringAndClear(); + + uno::Reference< XStatement > statement = m_pConnection->createStatement(); + uno::Reference< XResultSet > rs = statement->executeQuery(query.getStr()); + uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + + ODatabaseMetaDataResultSet::ORows aResults; + ODatabaseMetaDataResultSet::ORow aCurrentRow(19); + + aCurrentRow[0] = new ORowSetValueDecorator(); // Unused -- numbering starts from 0 + aCurrentRow[1] = new ORowSetValueDecorator(); // Catalog - can be null + aCurrentRow[2] = new ORowSetValueDecorator(); // Schema - can be null + aCurrentRow[8] = new ORowSetValueDecorator(); // Unused + aCurrentRow[10] = new ORowSetValueDecorator(sal_Int32(10)); // Radix: fixed in FB + aCurrentRow[14] = new ORowSetValueDecorator(); // Unused + aCurrentRow[15] = new ORowSetValueDecorator(); // Unused + + while( rs->next() ) + { + // 3. TABLE_NAME + aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1))); + // 4. Column Name + aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); + // 5. Datatype + short aType = getFBTypeFromBlrType(xRow->getShort(6)); + short aScale = xRow->getShort(10); + OUString sCharsetName = xRow->getString(13); + // result field may be filled with spaces + sCharsetName = sCharsetName.trim(); + ColumnTypeInfo aInfo(aType, xRow->getShort(7), aScale, + xRow->getString(13)); + + aCurrentRow[5] = new ORowSetValueDecorator(aInfo.getSdbcType()); + // 6. Typename (SQL_*) + aCurrentRow[6] = new ORowSetValueDecorator(aInfo.getColumnTypeName()); + + // 7. Column Sizes + { + sal_Int32 aColumnSize = 0; + switch (aType) + { + case SQL_TEXT: + case SQL_VARYING: + aColumnSize = xRow->getShort(12); + break; + case SQL_SHORT: + case SQL_LONG: + case SQL_FLOAT: + case SQL_DOUBLE: + case SQL_D_FLOAT: + case SQL_INT64: + case SQL_QUAD: + aColumnSize = xRow->getShort(9); + break; + case SQL_TIMESTAMP: + case SQL_BLOB: + case SQL_ARRAY: + case SQL_TYPE_TIME: + case SQL_TYPE_DATE: + case SQL_NULL: + // TODO: implement. + break; + } + aCurrentRow[7] = new ORowSetValueDecorator(aColumnSize); + } + + // 9. Decimal digits (scale) + // fb stores a negative number + aCurrentRow[9] = new ORowSetValueDecorator( static_cast<sal_Int16>(-aScale) ); + + // 11. Nullable + if (xRow->getShort(11)) + { + aCurrentRow[11] = new ORowSetValueDecorator(ColumnValue::NO_NULLS); + } + else + { + aCurrentRow[11] = new ORowSetValueDecorator(ColumnValue::NULLABLE); + } + // 12. Comments -- may be omitted + { + OUString aDescription; + uno::Reference< XBlob > xBlob = xRow->getBlob(3); + if (xBlob.is()) + { + const sal_Int64 aBlobLength = xBlob->length(); + if (aBlobLength > SAL_MAX_INT32) + { + SAL_WARN("connectivity.firebird", "getBytes can't return " << aBlobLength << " bytes but only max " << SAL_MAX_INT32); + aDescription = OUString(reinterpret_cast<char*>(xBlob->getBytes(1, SAL_MAX_INT32).getArray()), + SAL_MAX_INT32, + RTL_TEXTENCODING_UTF8); + } + else + { + aDescription = OUString(reinterpret_cast<char*>(xBlob->getBytes(1, static_cast<sal_Int32>(aBlobLength)).getArray()), + aBlobLength, + RTL_TEXTENCODING_UTF8); + } + } + aCurrentRow[12] = new ORowSetValueDecorator(aDescription); + } + // 13. Default -- may be omitted. + { + uno::Reference< XBlob > xDefaultValueBlob = xRow->getBlob(4); + if (xDefaultValueBlob.is()) + { + // TODO: Implement + } + aCurrentRow[13] = new ORowSetValueDecorator(); + } + + // 16. Bytes in Column for char + if (aType == SQL_TEXT) + { + aCurrentRow[16] = new ORowSetValueDecorator(xRow->getShort(8)); + } + else if (aType == SQL_VARYING) + { + aCurrentRow[16] = new ORowSetValueDecorator(sal_Int32(32767)); + } + else + { + aCurrentRow[16] = new ORowSetValueDecorator(sal_Int32(0)); + } + // 17. Index of column + { + short nColumnNumber = xRow->getShort(5); + // Firebird stores column numbers beginning with 0 internally + // SDBC expects column numbering to begin with 1. + aCurrentRow[17] = new ORowSetValueDecorator(sal_Int32(nColumnNumber + 1)); + } + // 18. Is nullable + if (xRow->getShort(9)) + { + aCurrentRow[18] = new ORowSetValueDecorator(OUString("NO")); + } + else + { + aCurrentRow[18] = new ORowSetValueDecorator(OUString("YES")); + } + + aResults.push_back(aCurrentRow); + } + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eColumns); + uno::Reference< XResultSet > xResultSet = pResultSet; + pResultSet->setRows( aResults ); + + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables( + const Any& /*catalog*/, + const OUString& /*schemaPattern*/, + const OUString& tableNamePattern, + const Sequence< OUString >& types) +{ + SAL_INFO("connectivity.firebird", "getTables() with " + "TableNamePattern: " << tableNamePattern); + + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables); + uno::Reference< XResultSet > xResultSet = pResultSet; + uno::Reference< XStatement > statement = m_pConnection->createStatement(); + + static const char wld[] = "%"; + OUStringBuffer queryBuf( + "SELECT " + "RDB$RELATION_NAME, " + "RDB$SYSTEM_FLAG, " + "RDB$RELATION_TYPE, " + "RDB$DESCRIPTION, " + "RDB$VIEW_BLR " + "FROM RDB$RELATIONS " + "WHERE "); + + // TODO: GLOBAL TEMPORARY, LOCAL TEMPORARY, ALIAS, SYNONYM + if (!types.hasElements() || (types.getLength() == 1 && types[0].match(wld))) + { + // All table types? I.e. includes system tables. + queryBuf.append("(RDB$RELATION_TYPE = 0 OR RDB$RELATION_TYPE = 1) "); + } + else + { + queryBuf.append("( (0 = 1) "); + for (OUString const & t : types) + { + if (t == "SYSTEM TABLE") + queryBuf.append("OR (RDB$SYSTEM_FLAG = 1 AND RDB$VIEW_BLR IS NULL) "); + else if (t == "TABLE") + queryBuf.append("OR (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0 AND RDB$VIEW_BLR IS NULL) "); + else if (t == "VIEW") + queryBuf.append("OR (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0 AND RDB$VIEW_BLR IS NOT NULL) "); + else + throw SQLException(); // TODO: implement other types, see above. + } + queryBuf.append(") "); + } + + if (!tableNamePattern.isEmpty()) + { + OUString sAppend; + if (tableNamePattern.match(wld)) + sAppend = "AND RDB$RELATION_NAME LIKE '%' "; + else + sAppend = "AND RDB$RELATION_NAME = '%' "; + + queryBuf.append(sAppend.replaceAll(wld, tableNamePattern)); + } + + queryBuf.append(" ORDER BY RDB$RELATION_TYPE, RDB$RELATION_NAME"); + + OUString query = queryBuf.makeStringAndClear(); + + uno::Reference< XResultSet > rs = statement->executeQuery(query.getStr()); + uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + ODatabaseMetaDataResultSet::ORows aResults; + + ODatabaseMetaDataResultSet::ORow aCurrentRow(6); + aCurrentRow[0] = new ORowSetValueDecorator(); // 0. Unused + aCurrentRow[1] = new ORowSetValueDecorator(); // 1. Table_Cat Unsupported + aCurrentRow[2] = new ORowSetValueDecorator(); // 2. Table_Schem Unsupported + + while( rs->next() ) + { + // 3. TABLE_NAME + aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1))); + // 4. TABLE_TYPE + { + // TODO: check this as the docs are a bit unclear. + sal_Int16 nSystemFlag = xRow->getShort(2); + sal_Int16 nTableType = xRow->getShort(3); + xRow->getBlob(5); // We have to retrieve a column to verify it is null. + bool aIsView = !xRow->wasNull(); + OUString sTableType; + + if (nSystemFlag == 1) + { + sTableType = "SYSTEM TABLE"; + } + else if (aIsView) + { + sTableType = "VIEW"; + } + else + { + if (nTableType == 0) + sTableType = "TABLE"; + } + + aCurrentRow[4] = new ORowSetValueDecorator(sTableType); + } + // 5. REMARKS + { + uno::Reference< XClob > xClob = xRow->getClob(4); + if (xClob.is()) + { + aCurrentRow[5] = new ORowSetValueDecorator(xClob->getSubString(0, xClob->length())); + } + } + + aResults.push_back(aCurrentRow); + } + + pResultSet->setRows( aResults ); + + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedureColumns( + const Any&, const OUString&, + const OUString&, const OUString& ) +{ + SAL_WARN("connectivity.firebird", "Not yet implemented"); + OSL_FAIL("Not implemented yet!"); + // TODO implement + return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eProcedureColumns); +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedures( + const Any&, const OUString&, + const OUString& ) +{ + SAL_WARN("connectivity.firebird", "Not yet implemented"); + OSL_FAIL("Not implemented yet!"); + // TODO implement + return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eProcedures); +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getVersionColumns( + const Any&, const OUString&, const OUString& ) +{ + SAL_WARN("connectivity.firebird", "Not yet implemented"); + OSL_FAIL("Not implemented yet!"); + // TODO implement + return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eVersionColumns); +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getExportedKeys( + const Any&, const OUString&, const OUString& table ) +{ + return ODatabaseMetaData::lcl_getKeys(false, table); +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getImportedKeys( + const Any&, const OUString&, const OUString& table ) +{ + return ODatabaseMetaData::lcl_getKeys(true, table); +} + +uno::Reference< XResultSet > ODatabaseMetaData::lcl_getKeys(const bool& bIsImport, const OUString& table ) +{ + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eImportedKeys); + uno::Reference< XResultSet > xResultSet = pResultSet; + + uno::Reference< XStatement > statement = m_pConnection->createStatement(); + + OUString sSQL = "SELECT " + "RDB$REF_CONSTRAINTS.RDB$UPDATE_RULE, " // 1 update rule + "RDB$REF_CONSTRAINTS.RDB$DELETE_RULE, " // 2 delete rule + "RDB$REF_CONSTRAINTS.RDB$CONST_NAME_UQ, " // 3 primary or unique key name + "RDB$REF_CONSTRAINTS.RDB$CONSTRAINT_NAME, " // 4 foreign key name + "PRIM.RDB$DEFERRABLE, " // 5 deferrability + "PRIM.RDB$INITIALLY_DEFERRED, " // 6 deferrability + "PRIM.RDB$RELATION_NAME, " // 7 PK table name + "PRIMARY_INDEX.RDB$FIELD_NAME, " // 8 PK column name + "PRIMARY_INDEX.RDB$FIELD_POSITION, " // 9 PK sequence number + "FOREI.RDB$RELATION_NAME, " // 10 FK table name + "FOREIGN_INDEX.RDB$FIELD_NAME " // 11 FK column name + "FROM RDB$REF_CONSTRAINTS " + "INNER JOIN RDB$RELATION_CONSTRAINTS AS PRIM " + "ON RDB$REF_CONSTRAINTS.RDB$CONST_NAME_UQ = PRIM.RDB$CONSTRAINT_NAME " + "INNER JOIN RDB$RELATION_CONSTRAINTS AS FOREI " + "ON RDB$REF_CONSTRAINTS.RDB$CONSTRAINT_NAME = FOREI.RDB$CONSTRAINT_NAME " + "INNER JOIN RDB$INDEX_SEGMENTS AS PRIMARY_INDEX " + "ON PRIM.RDB$INDEX_NAME = PRIMARY_INDEX.RDB$INDEX_NAME " + "INNER JOIN RDB$INDEX_SEGMENTS AS FOREIGN_INDEX " + "ON FOREI.RDB$INDEX_NAME = FOREIGN_INDEX.RDB$INDEX_NAME " + "WHERE FOREI.RDB$CONSTRAINT_TYPE = 'FOREIGN KEY' "; + if (bIsImport) + sSQL += "AND FOREI.RDB$RELATION_NAME = '"+ table +"'"; + else + sSQL += "AND PRIM.RDB$RELATION_NAME = '"+ table +"'"; + + uno::Reference< XResultSet > rs = statement->executeQuery(sSQL); + uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + + ODatabaseMetaDataResultSet::ORows aResults; + ODatabaseMetaDataResultSet::ORow aCurrentRow(15); + + // TODO is it necessary to initialize these? + aCurrentRow[0] = new ORowSetValueDecorator(); // Unused + aCurrentRow[1] = new ORowSetValueDecorator(); // PKTABLE_CAT unsupported + aCurrentRow[2] = new ORowSetValueDecorator(); // PKTABLE_SCHEM unsupported + aCurrentRow[5] = new ORowSetValueDecorator(); // FKTABLE_CAT unsupported + aCurrentRow[6] = new ORowSetValueDecorator(); // FKTABLE_SCHEM unsupported + + std::map< OUString,sal_Int32> aRuleMap; + aRuleMap[ OUString("CASCADE")] = KeyRule::CASCADE; + aRuleMap[ OUString("RESTRICT")] = KeyRule::RESTRICT; + aRuleMap[ OUString("SET NULL")] = KeyRule::SET_NULL; + aRuleMap[ OUString("SET DEFAULT")] = KeyRule::SET_DEFAULT; + aRuleMap[ OUString("NO ACTION")] = KeyRule::NO_ACTION; + + while(rs->next()) + { + aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(7))); // PK table + aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(8))); // PK column + aCurrentRow[7] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(10))); // FK table + aCurrentRow[8] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(11))); // FK column + + aCurrentRow[9] = new ORowSetValueDecorator(xRow->getShort(9)); // PK sequence number + aCurrentRow[10] = new ORowSetValueDecorator(aRuleMap[sanitizeIdentifier(xRow->getString(1))]); // update role + aCurrentRow[11] = new ORowSetValueDecorator(aRuleMap[sanitizeIdentifier(xRow->getString(2))]); // delete role + + aCurrentRow[12] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4))); // FK name + aCurrentRow[13] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // PK name + + aCurrentRow[14] = new ORowSetValueDecorator(Deferrability::NONE); // deferrability + + // deferrability is currently not supported, but may be supported in the future. + /* + aCurrentRow[14] = (xRow->getString(5) == "NO" ? + new ORowSetValueDecorator(Deferrability::NONE) + : (xRow->getString(6) == "NO" ? + new ORowSetValueDecorator(Deferrability::INITIALLY_IMMEDIATE) + : new ORowSetValueDecorator(Deferrability::INITIALLY_DEFERRED)); + */ + + aResults.push_back(aCurrentRow); + } + + pResultSet->setRows( aResults ); + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPrimaryKeys( + const Any& /*aCatalog*/, + const OUString& /*sSchema*/, + const OUString& sTable) +{ + SAL_INFO("connectivity.firebird", "getPrimaryKeys() with " + "Table: " << sTable); + + OUString sAppend = "WHERE constr.RDB$RELATION_NAME = '%' "; + OUString sQuery = "SELECT " + "constr.RDB$RELATION_NAME, " // 1. Table Name + "inds.RDB$FIELD_NAME, " // 2. Column Name + "inds.RDB$FIELD_POSITION, " // 3. Sequence Number + "constr.RDB$CONSTRAINT_NAME " // 4 Constraint name + "FROM RDB$RELATION_CONSTRAINTS constr " + "JOIN RDB$INDEX_SEGMENTS inds " + "on (constr.RDB$INDEX_NAME = inds.RDB$INDEX_NAME) " + + sAppend.replaceAll("%", sTable) + + "AND constr.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' " + "ORDER BY inds.RDB$FIELD_NAME"; + + uno::Reference< XStatement > xStatement = m_pConnection->createStatement(); + uno::Reference< XResultSet > xRs = xStatement->executeQuery(sQuery); + uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW ); + + ODatabaseMetaDataResultSet::ORows aResults; + ODatabaseMetaDataResultSet::ORow aCurrentRow(7); + + aCurrentRow[0] = new ORowSetValueDecorator(); // Unused -- numbering starts from 0 + aCurrentRow[1] = new ORowSetValueDecorator(); // Catalog - can be null + aCurrentRow[2] = new ORowSetValueDecorator(); // Schema - can be null + + while(xRs->next()) + { + // 3. Table Name + if (xRs->getRow() == 1) // Table name doesn't change, so only retrieve once + { + aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1))); + } + // 4. Column Name + aCurrentRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); + // 5. KEY_SEQ (which key in the sequence) + aCurrentRow[5] = new ORowSetValueDecorator(xRow->getShort(3)); + // 6. Primary Key Name + aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4))); + + aResults.push_back(aCurrentRow); + } + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::ePrimaryKeys); + uno::Reference< XResultSet > xResultSet = pResultSet; + pResultSet->setRows( aResults ); + + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo( + const Any& /*aCatalog*/, + const OUString& /*sSchema*/, + const OUString& sTable, + sal_Bool bIsUnique, + sal_Bool) // TODO: what is bIsApproximate? + +{ + // Apparently this method can also return a "tableIndexStatistic" + // However this is only mentioned in XDatabaseMetaData.idl (whose comments + // are duplicated in the postgresql driver), and is otherwise undocumented. + SAL_INFO("connectivity.firebird", "getPrimaryKeys() with " + "Table: " << sTable); + + OUStringBuffer aQueryBuf("SELECT " + "indices.RDB$RELATION_NAME, " // 1. Table Name + "index_segments.RDB$FIELD_NAME, " // 2. Column Name + "index_segments.RDB$FIELD_POSITION, " // 3. Sequence Number + "indices.RDB$INDEX_NAME, " // 4. Index name + "indices.RDB$UNIQUE_FLAG, " // 5. Unique Flag + "indices.RDB$INDEX_TYPE " // 6. Index Type + "FROM RDB$INDICES indices " + "JOIN RDB$INDEX_SEGMENTS index_segments " + "on (indices.RDB$INDEX_NAME = index_segments.RDB$INDEX_NAME) " + "WHERE indices.RDB$RELATION_NAME = '" + sTable + "' " + "AND (indices.RDB$SYSTEM_FLAG = 0) "); + // Not sure whether we should exclude system indices, but otoh. we never + // actually deal with system tables (system indices only apply to system + // tables) within the GUI. + + // Only filter if true (according to the docs), i.e.: + // If false we return all indices, if true we return only unique indices + if (bIsUnique) + aQueryBuf.append("AND (indices.RDB$UNIQUE_FLAG = 1) "); + + OUString sQuery = aQueryBuf.makeStringAndClear(); + + uno::Reference< XStatement > xStatement = m_pConnection->createStatement(); + uno::Reference< XResultSet > xRs = xStatement->executeQuery(sQuery); + uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW ); + + ODatabaseMetaDataResultSet::ORows aResults; + ODatabaseMetaDataResultSet::ORow aCurrentRow(14); + + aCurrentRow[0] = new ORowSetValueDecorator(); // Unused -- numbering starts from 0 + aCurrentRow[1] = new ORowSetValueDecorator(); // Catalog - can be null + aCurrentRow[2] = new ORowSetValueDecorator(); // Schema - can be null + aCurrentRow[5] = new ORowSetValueDecorator(); // Index Catalog -- can be null + // Wikipedia indicates: + // 'Firebird makes all indices of the database behave like well-tuned "clustered indexes" used by other architectures.' + // but it's not "CLUSTERED", neither "STATISTIC" nor "HASHED" (the other specific types from offapi/com/sun/star/sdbc/IndexType.idl) + // According to https://www.ibphoenix.com/resources/documents/design/doc_18, + // it seems another type => OTHER + aCurrentRow[7] = new ORowSetValueDecorator(IndexType::OTHER); // 7. INDEX TYPE + aCurrentRow[13] = new ORowSetValueDecorator(); // Filter Condition -- can be null + + while(xRs->next()) + { + // 3. Table Name + if (xRs->getRow() == 1) // Table name doesn't change, so only retrieve once + { + aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1))); + } + + // 4. NON_UNIQUE -- i.e. specifically negate here. + aCurrentRow[4] = new ORowSetValueDecorator(xRow->getShort(5) == 0); + // 6. INDEX NAME + aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4))); + + // 8. ORDINAL POSITION + aCurrentRow[8] = new ORowSetValueDecorator(xRow->getShort(3)); + // 9. COLUMN NAME + aCurrentRow[9] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); + // 10. ASC(ending)/DESC(ending) + if (xRow->getShort(6) == 1) + aCurrentRow[10] = new ORowSetValueDecorator(OUString("D")); + else + aCurrentRow[10] = new ORowSetValueDecorator(OUString("A")); + // TODO: double check this^^^, doesn't seem to be officially documented anywhere. + // 11. CARDINALITY + aCurrentRow[11] = new ORowSetValueDecorator(sal_Int32(0)); // TODO: determine how to do this + // 12. PAGES + aCurrentRow[12] = new ORowSetValueDecorator(sal_Int32(0)); // TODO: determine how to do this + + aResults.push_back(aCurrentRow); + } + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::ePrimaryKeys); + uno::Reference< XResultSet > xResultSet = pResultSet; + pResultSet->setRows( aResults ); + + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getBestRowIdentifier( + const Any&, const OUString&, const OUString&, sal_Int32, + sal_Bool ) +{ + OSL_FAIL("Not implemented yet!"); + // TODO implement + return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eBestRowIdentifier); +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges( + const Any& /*aCatalog*/, + const OUString& /*sSchemaPattern*/, + const OUString& sTableNamePattern) +{ + SAL_INFO("connectivity.firebird", "getTablePrivileges() with " + "TableNamePattern: " << sTableNamePattern); + + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTablePrivileges); + uno::Reference< XResultSet > xResultSet = pResultSet; + uno::Reference< XStatement > statement = m_pConnection->createStatement(); + + // TODO: column specific privileges are included, we may need + // to have WHERE RDB$FIELD_NAME = NULL or similar. + static const char wld[] = "%"; + OUStringBuffer queryBuf( + "SELECT " + "priv.RDB$RELATION_NAME, " // 1 + "priv.RDB$GRANTOR," // 2 + "priv.RDB$USER, " // 3 Grantee + "priv.RDB$PRIVILEGE, " // 4 + "priv.RDB$GRANT_OPTION " // 5 is Grantable + "FROM RDB$USER_PRIVILEGES priv "); + + if (!sTableNamePattern.isEmpty()) + { + OUString sAppend; + if (sTableNamePattern.match(wld)) + sAppend = "WHERE priv.RDB$RELATION_NAME LIKE '%' "; + else + sAppend = "WHERE priv.RDB$RELATION_NAME = '%' "; + + queryBuf.append(sAppend.replaceAll(wld, sTableNamePattern)); + } + queryBuf.append(" ORDER BY priv.RDB$RELATION_TYPE, " + "priv.RDB$RELATION_NAME, " + "priv.RDB$PRIVILEGE"); + + OUString query = queryBuf.makeStringAndClear(); + + uno::Reference< XResultSet > rs = statement->executeQuery(query.getStr()); + uno::Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + ODatabaseMetaDataResultSet::ORows aResults; + + ODatabaseMetaDataResultSet::ORow aRow(8); + aRow[0] = new ORowSetValueDecorator(); // Unused + aRow[1] = new ORowSetValueDecorator(); // TABLE_CAT unsupported + aRow[2] = new ORowSetValueDecorator(); // TABLE_SCHEM unsupported. + + while( rs->next() ) + { + // 3. TABLE_NAME + aRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1))); + aRow[4] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); // 4. GRANTOR + aRow[5] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(3))); // 5. GRANTEE + aRow[6] = new ORowSetValueDecorator(xRow->getString(4)); // 6. Privilege + aRow[7] = new ORowSetValueDecorator(bool(xRow->getBoolean(5))); // 7. Is Grantable + + aResults.push_back(aRow); + } + + pResultSet->setRows( aResults ); + + return xResultSet; +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCrossReference( + const Any&, const OUString&, + const OUString&, const Any&, + const OUString&, const OUString& ) +{ + OSL_FAIL("Not implemented yet!"); + // TODO implement + return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eCrossReference); +} + +uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any&, const OUString&, const OUString&, const Sequence< sal_Int32 >& ) +{ + OSL_FAIL("Not implemented yet!"); + // TODO implement + return new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eUDTs); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.hxx b/connectivity/source/drivers/firebird/DatabaseMetaData.hxx new file mode 100644 index 000000000..95e744bcf --- /dev/null +++ b/connectivity/source/drivers/firebird/DatabaseMetaData.hxx @@ -0,0 +1,205 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_DATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_DATABASEMETADATA_HXX + +#include "Connection.hxx" + +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity +{ + namespace firebird + { + + //************ Class: ODatabaseMetaData + + + typedef ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData> ODatabaseMetaData_BASE; + + class ODatabaseMetaData : public ODatabaseMetaData_BASE + { + ::rtl::Reference<Connection> m_pConnection; + private: + css::uno::Reference< css::sdbc::XResultSet > lcl_getKeys( const bool& bIsImport, const OUString& table ); + public: + + explicit ODatabaseMetaData(Connection* _pCon); + virtual ~ODatabaseMetaData() override; + + // as I mentioned before this interface is really BIG + // XDatabaseMetaData + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override; + virtual OUString SAL_CALL getIdentifierQuoteString( ) override; + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL isCatalogAtStart( ) override; + virtual OUString SAL_CALL getCatalogSeparator( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxStatements( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_DATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Driver.cxx b/connectivity/source/drivers/firebird/Driver.cxx new file mode 100644 index 000000000..aa6f0d9d5 --- /dev/null +++ b/connectivity/source/drivers/firebird/Driver.cxx @@ -0,0 +1,242 @@ +/* -*- 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 "Connection.hxx" +#include "Driver.hxx" +#include "SubComponent.hxx" + +#include <connectivity/dbexception.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + +#include <comphelper/processfactory.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/file.hxx> +#include <osl/process.h> +#include <rtl/bootstrap.hxx> +#include <sal/log.hxx> +#include <unotools/localfilehelper.hxx> + +using namespace com::sun::star; +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::sdbcx; + +using namespace ::osl; + +using namespace connectivity::firebird; + +namespace connectivity::firebird +{ + Reference< XInterface > FirebirdDriver_CreateInstance( + const Reference< XMultiServiceFactory >& _rxFactory) + { + SAL_INFO("connectivity.firebird", "FirebirdDriver_CreateInstance()" ); + return *(new FirebirdDriver(comphelper::getComponentContext(_rxFactory))); + } +} + +// Static const variables +namespace { +const char our_sFirebirdTmpVar[] = "FIREBIRD_TMP"; +const char our_sFirebirdLockVar[] = "FIREBIRD_LOCK"; +const char our_sFirebirdMsgVar[] = "FIREBIRD_MSG"; +#ifdef MACOSX +const char our_sFirebirdLibVar[] = "LIBREOFFICE_FIREBIRD_LIB"; +#endif +}; + +FirebirdDriver::FirebirdDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) + : ODriver_BASE(m_aMutex) + , m_aContext(_rxContext) + , m_firebirdTMPDirectory(nullptr, true) + , m_firebirdLockDirectory(nullptr, true) +{ + // ::utl::TempFile uses a unique temporary directory (subdirectory of + // /tmp or other user specific tmp directory) per instance in which + // we can create directories for firebird at will. + + // Overrides firebird's default of /tmp or c:\temp + osl_setEnvironment(OUString(our_sFirebirdTmpVar).pData, m_firebirdTMPDirectory.GetFileName().pData); + + // Overrides firebird's default of /tmp/firebird or c:\temp\firebird + osl_setEnvironment(OUString(our_sFirebirdLockVar).pData, m_firebirdLockDirectory.GetFileName().pData); + +#ifndef SYSTEM_FIREBIRD + // Overrides firebird's hardcoded default of /usr/local/firebird on *nix, + // however on Windows it seems to use the current directory as a default. + OUString sMsgURL("$BRAND_BASE_DIR/$BRAND_SHARE_SUBDIR/firebird"); + ::rtl::Bootstrap::expandMacros(sMsgURL); + OUString sMsgPath; + ::osl::FileBase::getSystemPathFromFileURL(sMsgURL, sMsgPath); + osl_setEnvironment(OUString(our_sFirebirdMsgVar).pData, sMsgPath.pData); +#ifdef MACOSX + // Set an env. variable to specify library location + // for dlopen used in fbclient. + OUString sLibURL("$LO_LIB_DIR"); + ::rtl::Bootstrap::expandMacros(sLibURL); + OUString sLibPath; + ::osl::FileBase::getSystemPathFromFileURL(sLibURL, sLibPath); + osl_setEnvironment(OUString(our_sFirebirdLibVar).pData, sLibPath.pData); +#endif /*MACOSX*/ +#endif /*!SYSTEM_FIREBIRD*/ +} + +FirebirdDriver::~FirebirdDriver() +{ + utl::removeTree(m_firebirdTMPDirectory.GetURL()); + utl::removeTree(m_firebirdLockDirectory.GetURL()); +} + +void FirebirdDriver::disposing() +{ + MutexGuard aGuard(m_aMutex); + + for (auto const& elem : m_xConnections) + { + Reference< XComponent > xComp(elem.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + } + m_xConnections.clear(); + + osl_clearEnvironment(OUString(our_sFirebirdTmpVar).pData); + osl_clearEnvironment(OUString(our_sFirebirdLockVar).pData); + +#ifndef SYSTEM_FIREBIRD + osl_clearEnvironment(OUString(our_sFirebirdMsgVar).pData); +#ifdef MACOSX + osl_clearEnvironment(OUString(our_sFirebirdLibVar).pData); +#endif /*MACOSX*/ +#endif /*!SYSTEM_FIREBIRD*/ + + OSL_VERIFY(fb_shutdown(0, 1)); + + ODriver_BASE::disposing(); +} + +//----- static ServiceInfo --------------------------------------------------- +OUString FirebirdDriver::getImplementationName_Static() +{ + return "com.sun.star.comp.sdbc.firebird.Driver"; +} + +Sequence< OUString > FirebirdDriver::getSupportedServiceNames_Static() +{ + return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" }; +} + +OUString SAL_CALL FirebirdDriver::getImplementationName() +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL FirebirdDriver::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > SAL_CALL FirebirdDriver::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +// ---- XDriver ------------------------------------------------------------- +Reference< XConnection > SAL_CALL FirebirdDriver::connect( + const OUString& url, const Sequence< PropertyValue >& info ) +{ + SAL_INFO("connectivity.firebird", "connect(), URL: " << url ); + + MutexGuard aGuard( m_aMutex ); + if (ODriver_BASE::rBHelper.bDisposed) + throw DisposedException(); + + if ( ! acceptsURL(url) ) + return nullptr; + + Connection* pCon = new Connection(); + Reference< XConnection > xCon = pCon; + pCon->construct(url, info); + + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + + return xCon; +} + +sal_Bool SAL_CALL FirebirdDriver::acceptsURL( const OUString& url ) +{ + return (url == "sdbc:embedded:firebird" || url.startsWith("sdbc:firebird:")); +} + +Sequence< DriverPropertyInfo > SAL_CALL FirebirdDriver::getPropertyInfo( + const OUString& url, const Sequence< PropertyValue >& ) +{ + if ( ! acceptsURL(url) ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + return Sequence< DriverPropertyInfo >(); +} + +sal_Int32 SAL_CALL FirebirdDriver::getMajorVersion( ) +{ + // The major and minor version are sdbc driver specific. Must begin with 1.0 + // as per https://api.libreoffice.org/docs/common/ref/com/sun/star/sdbc/XDriver.html + return 1; +} + +sal_Int32 SAL_CALL FirebirdDriver::getMinorVersion( ) +{ + return 0; +} + +//----- XDataDefinitionSupplier +uno::Reference< XTablesSupplier > SAL_CALL FirebirdDriver::getDataDefinitionByConnection( + const uno::Reference< XConnection >& rConnection) +{ + Connection* pConnection = static_cast< Connection* >(rConnection.get()); + return pConnection->createCatalog(); +} + +uno::Reference< XTablesSupplier > SAL_CALL FirebirdDriver::getDataDefinitionByURL( + const OUString& rURL, + const uno::Sequence< PropertyValue >& rInfo) +{ + uno::Reference< XConnection > xConnection = connect(rURL, rInfo); + return getDataDefinitionByConnection(xConnection); +} + +namespace connectivity::firebird +{ + void checkDisposed(bool _bThrow) + { + if (_bThrow) + throw DisposedException(); + + } + +} // namespace + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Driver.hxx b/connectivity/source/drivers/firebird/Driver.hxx new file mode 100644 index 000000000..8fcf17fa2 --- /dev/null +++ b/connectivity/source/drivers/firebird/Driver.hxx @@ -0,0 +1,102 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_DRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_DRIVER_HXX + +#include "Connection.hxx" + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <cppuhelper/compbase.hxx> +#include <unotools/tempfile.hxx> + +namespace connectivity +{ + namespace firebird + { + // The SQL dialect in use + // Has to be used in various isc_* calls. + // 3: Is IB6 -- minimum required for delimited identifiers. + static const int FIREBIRD_SQL_DIALECT = 3; + + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > FirebirdDriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver, + css::sdbcx::XDataDefinitionSupplier, + css::lang::XServiceInfo > ODriver_BASE; + + class FirebirdDriver : public ODriver_BASE + { + private: + css::uno::Reference<css::uno::XComponentContext> m_aContext; + ::utl::TempFile m_firebirdTMPDirectory; + ::utl::TempFile m_firebirdLockDirectory; + + protected: + ::osl::Mutex m_aMutex; // mutex is need to control member access + OWeakRefArray m_xConnections; // vector containing a list + // of all the Connection objects + // for this Driver + + public: + + explicit FirebirdDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + virtual ~FirebirdDriver() override; + const css::uno::Reference<css::uno::XComponentContext>& getContext() const { return m_aContext; } + + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + + // XDataDefinitionSupplier + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > + SAL_CALL getDataDefinitionByConnection( + const css::uno::Reference< css::sdbc::XConnection >& rxConnection) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > + SAL_CALL getDataDefinitionByURL( + const OUString& rsURL, + const css::uno::Sequence< css::beans::PropertyValue >& rInfo) override; + }; + } + +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_DRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Indexes.cxx b/connectivity/source/drivers/firebird/Indexes.cxx new file mode 100644 index 000000000..86f4f9f6f --- /dev/null +++ b/connectivity/source/drivers/firebird/Indexes.cxx @@ -0,0 +1,32 @@ +/* -*- 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/. + */ + +#include "Indexes.hxx" + +using namespace ::connectivity; +using namespace ::connectivity::firebird; + +using namespace ::osl; +using namespace ::std; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdbc; + +Indexes::Indexes(Table* pTable, Mutex& rMutex, const vector< OUString>& rVector) + : OIndexesHelper(pTable, rMutex, rVector) + , m_pTable(pTable) +{ +} + +// XDrop +void Indexes::dropObject(sal_Int32 /*nPosition*/, const OUString& sIndexName) +{ + OUString sSql("DROP INDEX \"" + sIndexName +"\""); + m_pTable->getConnection()->createStatement()->execute(sSql); +} diff --git a/connectivity/source/drivers/firebird/Indexes.hxx b/connectivity/source/drivers/firebird/Indexes.hxx new file mode 100644 index 000000000..364b36b04 --- /dev/null +++ b/connectivity/source/drivers/firebird/Indexes.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_INDEXES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_INDEXES_HXX + +#include "Table.hxx" + +#include <connectivity/TIndexes.hxx> + +namespace connectivity +{ + namespace firebird + { + + /** + * Firebird has a non-standard DROP INDEX statement, hence we need + * to override OIndexesHelper::dropObject + */ + class Indexes: public ::connectivity::OIndexesHelper + { + private: + Table* m_pTable; + protected: + // XDrop + virtual void dropObject(sal_Int32 nPosition, + const OUString& sIndexName) override; + public: + Indexes(Table* pTable, + ::osl::Mutex& rMutex, + const std::vector< OUString>& rVector); + }; + + } // namespace firebird +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_INDEXES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Keys.cxx b/connectivity/source/drivers/firebird/Keys.cxx new file mode 100644 index 000000000..dd4cca47f --- /dev/null +++ b/connectivity/source/drivers/firebird/Keys.cxx @@ -0,0 +1,54 @@ +/* -*- 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/. + */ + +#include "Keys.hxx" +#include "Table.hxx" + +#include <connectivity/dbtools.hxx> + +using namespace ::connectivity; +using namespace ::connectivity::firebird; + +using namespace ::dbtools; +using namespace ::osl; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +Keys::Keys(Table* pTable, Mutex& rMutex, const ::std::vector< OUString>& rNames): + OKeysHelper(pTable, + rMutex, + rNames), + m_pTable(pTable) +{ +} + +//----- XDrop ---------------------------------------------------------------- +void Keys::dropObject(sal_Int32 nPosition, const OUString& sName) +{ + if (m_pTable->isNew()) + return; + + uno::Reference<XPropertySet> xKey(getObject(nPosition), UNO_QUERY); + + if (xKey.is()) + { + const OUString sQuote = m_pTable->getConnection()->getMetaData() + ->getIdentifierQuoteString(); + + OUString sSql("ALTER TABLE " + quoteName(sQuote, m_pTable->getName()) + + " DROP CONSTRAINT " + quoteName(sQuote, sName)); + + m_pTable->getConnection()->createStatement()->execute(sSql); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Keys.hxx b/connectivity/source/drivers/firebird/Keys.hxx new file mode 100644 index 000000000..143dbbf54 --- /dev/null +++ b/connectivity/source/drivers/firebird/Keys.hxx @@ -0,0 +1,41 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_KEYS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_KEYS_HXX + +#include <connectivity/TKeys.hxx> + +namespace connectivity +{ + + namespace firebird + { + + class Table; + + class Keys: public ::connectivity::OKeysHelper + { + private: + Table* m_pTable; + + public: + Keys(Table* pTable, + ::osl::Mutex& rMutex, + const ::std::vector< OUString>& rNames); + + // OKeysHelper / XDrop + void dropObject(sal_Int32 nPosition, const OUString& sName) override; + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_KEYS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/PreparedStatement.cxx b/connectivity/source/drivers/firebird/PreparedStatement.cxx new file mode 100644 index 000000000..e4510b758 --- /dev/null +++ b/connectivity/source/drivers/firebird/PreparedStatement.cxx @@ -0,0 +1,1018 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <cmath> + +#include <string_view> + +#include "Connection.hxx" +#include "PreparedStatement.hxx" +#include "ResultSet.hxx" +#include "ResultSetMetaData.hxx" +#include "Util.hxx" + +#include <comphelper/sequence.hxx> +#include <connectivity/dbexception.hxx> +#include <propertyids.hxx> +#include <connectivity/dbtools.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/sdbc/DataType.hpp> + +using namespace connectivity::firebird; + +using namespace ::comphelper; +using namespace ::osl; + +using namespace com::sun::star; +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::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.firebird.PreparedStatement","com.sun.star.sdbc.PreparedStatement"); + + +OPreparedStatement::OPreparedStatement( Connection* _pConnection, + const OUString& sql) + :OStatementCommonBase(_pConnection) + ,m_sSqlStatement(sql) + ,m_pOutSqlda(nullptr) + ,m_pInSqlda(nullptr) +{ + SAL_INFO("connectivity.firebird", "OPreparedStatement(). " + "sql: " << sql); +} + +void OPreparedStatement::ensurePrepared() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + + if (m_aStatementHandle) + return; + + ISC_STATUS aErr = 0; + + if (!m_pInSqlda) + { + m_pInSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(10))); + m_pInSqlda->version = SQLDA_VERSION1; + m_pInSqlda->sqln = 10; + } + + prepareAndDescribeStatement(m_sSqlStatement, + m_pOutSqlda, + m_pInSqlda); + + aErr = isc_dsql_describe_bind(m_statusVector, + &m_aStatementHandle, + 1, + m_pInSqlda); + + if (aErr) + { + SAL_WARN("connectivity.firebird", "isc_dsql_describe_bind failed"); + } + else if (m_pInSqlda->sqld > m_pInSqlda->sqln) // Not large enough + { + short nItems = m_pInSqlda->sqld; + free(m_pInSqlda); + m_pInSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(nItems))); + m_pInSqlda->version = SQLDA_VERSION1; + m_pInSqlda->sqln = nItems; + aErr = isc_dsql_describe_bind(m_statusVector, + &m_aStatementHandle, + 1, + m_pInSqlda); + SAL_WARN_IF(aErr, "connectivity.firebird", "isc_dsql_describe_bind failed"); + } + + if (!aErr) + mallocSQLVAR(m_pInSqlda); + else + evaluateStatusVector(m_statusVector, m_sSqlStatement, *this); +} + +OPreparedStatement::~OPreparedStatement() +{ +} + +void SAL_CALL OPreparedStatement::acquire() throw() +{ + OStatementCommonBase::acquire(); +} + +void SAL_CALL OPreparedStatement::release() throw() +{ + OStatementCommonBase::release(); +} + +Any SAL_CALL OPreparedStatement::queryInterface(const Type& rType) +{ + Any aRet = OStatementCommonBase::queryInterface(rType); + if(!aRet.hasValue()) + aRet = OPreparedStatement_Base::queryInterface(rType); + return aRet; +} + +uno::Sequence< Type > SAL_CALL OPreparedStatement::getTypes() +{ + return concatSequences(OPreparedStatement_Base::getTypes(), + OStatementCommonBase::getTypes()); +} + +Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + ensurePrepared(); + + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(m_pConnection.get() + , m_pOutSqlda); + + return m_xMetaData; +} + +void SAL_CALL OPreparedStatement::close() +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + + OStatementCommonBase::close(); + if (m_pInSqlda) + { + freeSQLVAR(m_pInSqlda); + free(m_pInSqlda); + m_pInSqlda = nullptr; + } + if (m_pOutSqlda) + { + freeSQLVAR(m_pOutSqlda); + free(m_pOutSqlda); + m_pOutSqlda = nullptr; + } +} + +void SAL_CALL OPreparedStatement::disposing() +{ + close(); +} + +void SAL_CALL OPreparedStatement::setString(sal_Int32 nParameterIndex, + const OUString& sInput) +{ + SAL_INFO("connectivity.firebird", + "setString(" << nParameterIndex << " , " << sInput << ")"); + + MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + ensurePrepared(); + + checkParameterIndex(nParameterIndex); + setParameterNull(nParameterIndex, false); + + OString str = OUStringToOString(sInput , RTL_TEXTENCODING_UTF8 ); + + XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1); + + int dtype = (pVar->sqltype & ~1); // drop flag bit for now + + if (str.getLength() > pVar->sqllen) + str = str.copy(0, pVar->sqllen); + + switch (dtype) { + case SQL_VARYING: + { + const sal_Int32 max_varchar_len = 0xFFFF; + // First 2 bytes indicate string size + if (str.getLength() > max_varchar_len) + { + str = str.copy(0, max_varchar_len); + } + const auto nLength = str.getLength(); + memcpy(pVar->sqldata, &nLength, 2); + // Actual data + memcpy(pVar->sqldata + 2, str.getStr(), str.getLength()); + break; + } + case SQL_TEXT: + memcpy(pVar->sqldata, str.getStr(), str.getLength()); + // Fill remainder with spaces + memset(pVar->sqldata + str.getLength(), ' ', pVar->sqllen - str.getLength()); + break; + case SQL_BLOB: // Clob + assert( pVar->sqlsubtype == static_cast<short>(BlobSubtype::Clob) ); + setClob(nParameterIndex, sInput ); + break; + case SQL_SHORT: + { + sal_Int32 int32Value = sInput.toInt32(); + if ( (int32Value < std::numeric_limits<sal_Int16>::min()) || + (int32Value > std::numeric_limits<sal_Int16>::max()) ) + { + ::dbtools::throwSQLException( + "Value out of range for SQL_SHORT type", + ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, + *this); + } + setShort(nParameterIndex, int32Value); + break; + } + case SQL_LONG: + { + sal_Int32 int32Value = sInput.toInt32(); + setInt(nParameterIndex, int32Value); + break; + } + case SQL_INT64: + { + sal_Int64 int64Value = sInput.toInt64(); + setLong(nParameterIndex, int64Value); + break; + } + case SQL_FLOAT: + { + float floatValue = sInput.toFloat(); + setFloat(nParameterIndex, floatValue); + break; + } + case SQL_BOOLEAN: + { + bool boolValue = sInput.toBoolean(); + setBoolean(nParameterIndex, boolValue); + break; + } + default: + ::dbtools::throwSQLException( + "Incorrect type for setString", + ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, + *this); + } +} + +Reference< XConnection > SAL_CALL OPreparedStatement::getConnection() +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + + return Reference<XConnection>(m_pConnection.get()); +} + +sal_Bool SAL_CALL OPreparedStatement::execute() +{ + SAL_INFO("connectivity.firebird", "executeQuery(). " + "Got called with sql: " << m_sSqlStatement); + + MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + + ensurePrepared(); + + ISC_STATUS aErr; + + if (m_xResultSet.is()) // Checks whether we have already run the statement. + { + disposeResultSet(); + // Closes the cursor from the last run. + // This doesn't actually free the statement -- using DSQL_close closes + // the cursor and keeps the statement, using DSQL_drop frees the statement + // (and associated cursors). + aErr = isc_dsql_free_statement(m_statusVector, + &m_aStatementHandle, + DSQL_close); + if (aErr) + { + // Do not throw error. Trying to close a closed cursor is not a + // critical mistake. + OUString sErrMsg = StatusVectorToString(m_statusVector, + "isc_dsql_free_statement: close cursor"); + SAL_WARN("connectivity.firebird", sErrMsg); + } + } + + aErr = isc_dsql_execute(m_statusVector, + &m_pConnection->getTransaction(), + &m_aStatementHandle, + 1, + m_pInSqlda); + if (aErr) + { + SAL_WARN("connectivity.firebird", "isc_dsql_execute failed" ); + evaluateStatusVector(m_statusVector, "isc_dsql_execute", *this); + } + + m_xResultSet = new OResultSet(m_pConnection.get(), + m_aMutex, + uno::Reference< XInterface >(*this), + m_aStatementHandle, + m_pOutSqlda); + + if (getStatementChangeCount() > 0) + m_pConnection->notifyDatabaseModified(); + + return m_xResultSet.is(); + // TODO: implement handling of multiple ResultSets. +} + +sal_Int32 SAL_CALL OPreparedStatement::executeUpdate() +{ + execute(); + return getStatementChangeCount(); +} + +Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery() +{ + execute(); + return m_xResultSet; +} + +namespace { + +/** + * Take out the number part of a fix point decimal without + * the information of where is the fractional part from a + * string representation of a number. (e.g. 54.654 -> 54654) + */ +sal_Int64 toNumericWithoutDecimalPlace(const OUString& sSource) +{ + OUString sNumber(sSource); + + // cut off leading 0 eventually ( eg. 0.567 -> .567) + (void)sSource.startsWith("0", &sNumber); + + sal_Int32 nDotIndex = sNumber.indexOf('.'); + + if( nDotIndex < 0) + { + return sNumber.toInt64(); // no dot -> it's an integer + } + else + { + // remove dot + OUStringBuffer sBuffer(15); + if(nDotIndex > 0) + { + sBuffer.append(std::u16string_view(sNumber).substr(0, nDotIndex)); + } + sBuffer.append(std::u16string_view(sNumber).substr(nDotIndex + 1)); + return sBuffer.makeStringAndClear().toInt64(); + } +} + +} + +//----- XParameters ----------------------------------------------------------- +void SAL_CALL OPreparedStatement::setNull(sal_Int32 nIndex, sal_Int32 /*nSqlType*/) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + ensurePrepared(); + + checkParameterIndex(nIndex); + setParameterNull(nIndex); +} + +void SAL_CALL OPreparedStatement::setBoolean(sal_Int32 nIndex, sal_Bool bValue) +{ + setValue< sal_Bool >(nIndex, bValue, SQL_BOOLEAN); +} + +template <typename T> +void OPreparedStatement::setValue(sal_Int32 nIndex, const T& nValue, ISC_SHORT nType) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + ensurePrepared(); + + checkParameterIndex(nIndex); + setParameterNull(nIndex, false); + + XSQLVAR* pVar = m_pInSqlda->sqlvar + (nIndex - 1); + + if ((pVar->sqltype & ~1) != nType) + { + ::dbtools::throwSQLException( + "Incorrect type for setValue", + ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, + *this); + } + + memcpy(pVar->sqldata, &nValue, sizeof(nValue)); +} + +void SAL_CALL OPreparedStatement::setByte(sal_Int32 nIndex, sal_Int8 nValue) +{ + // there's no TINYINT or equivalent on Firebird, + // so do the same as setShort + setValue< sal_Int16 >(nIndex, nValue, SQL_SHORT); +} + +void SAL_CALL OPreparedStatement::setShort(sal_Int32 nIndex, sal_Int16 nValue) +{ + setValue< sal_Int16 >(nIndex, nValue, SQL_SHORT); +} + +void SAL_CALL OPreparedStatement::setInt(sal_Int32 nIndex, sal_Int32 nValue) +{ + setValue< sal_Int32 >(nIndex, nValue, SQL_LONG); +} + +void SAL_CALL OPreparedStatement::setLong(sal_Int32 nIndex, sal_Int64 nValue) +{ + setValue< sal_Int64 >(nIndex, nValue, SQL_INT64); +} + +void SAL_CALL OPreparedStatement::setFloat(sal_Int32 nIndex, float nValue) +{ + setValue< float >(nIndex, nValue, SQL_FLOAT); +} + +void SAL_CALL OPreparedStatement::setDouble(sal_Int32 nIndex, double nValue) +{ + MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + ensurePrepared(); + + XSQLVAR* pVar = m_pInSqlda->sqlvar + (nIndex - 1); + short dType = (pVar->sqltype & ~1); // drop flag bit for now + short dSubType = pVar->sqlsubtype; + // Assume it is a sub type of a number. + if(dSubType < 0 || dSubType > 2) + { + ::dbtools::throwSQLException( + "Incorrect number sub type", + ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, + *this); + } + // firebird stores scale as a negative number + ColumnTypeInfo columnType{ dType, dSubType, + static_cast<short>(-pVar->sqlscale) }; + + // Caller might try to set an integer type here. It makes sense to convert + // it instead of throwing an error. + switch(columnType.getSdbcType()) + { + case DataType::SMALLINT: + setValue< sal_Int16 >(nIndex, + static_cast<sal_Int16>(nValue), + dType); + break; + case DataType::INTEGER: + setValue< sal_Int32 >(nIndex, + static_cast<sal_Int32>(nValue), + dType); + break; + case DataType::BIGINT: + setValue< sal_Int64 >(nIndex, + static_cast<sal_Int64>(nValue), + dType); + break; + case DataType::NUMERIC: + case DataType::DECIMAL: + // take decimal places into account, later on they are removed in makeNumericString + setObjectWithInfo(nIndex,Any{nValue}, columnType.getSdbcType(), columnType.getScale()); + break; + default: + setValue< double >(nIndex, nValue, SQL_DOUBLE); // TODO: SQL_D_FLOAT? + } +} + +void SAL_CALL OPreparedStatement::setDate(sal_Int32 nIndex, const Date& rDate) +{ + struct tm aCTime; + aCTime.tm_mday = rDate.Day; + aCTime.tm_mon = rDate.Month -1; + aCTime.tm_year = rDate.Year -1900; + + ISC_DATE aISCDate; + isc_encode_sql_date(&aCTime, &aISCDate); + + setValue< ISC_DATE >(nIndex, aISCDate, SQL_TYPE_DATE); +} + +void SAL_CALL OPreparedStatement::setTime( sal_Int32 nIndex, const css::util::Time& rTime) +{ + struct tm aCTime; + aCTime.tm_sec = rTime.Seconds; + aCTime.tm_min = rTime.Minutes; + aCTime.tm_hour = rTime.Hours; + + ISC_TIME aISCTime; + isc_encode_sql_time(&aCTime, &aISCTime); + + // Here we "know" that ISC_TIME is simply in units of seconds/ISC_TIME_SECONDS_PRECISION with no + // other funkiness, so we can simply add the fraction of a second. + aISCTime += rTime.NanoSeconds / (1000000000 / ISC_TIME_SECONDS_PRECISION); + + setValue< ISC_TIME >(nIndex, aISCTime, SQL_TYPE_TIME); +} + +void SAL_CALL OPreparedStatement::setTimestamp(sal_Int32 nIndex, const DateTime& rTimestamp) +{ + struct tm aCTime; + aCTime.tm_sec = rTimestamp.Seconds; + aCTime.tm_min = rTimestamp.Minutes; + aCTime.tm_hour = rTimestamp.Hours; + aCTime.tm_mday = rTimestamp.Day; + aCTime.tm_mon = rTimestamp.Month - 1; + aCTime.tm_year = rTimestamp.Year - 1900; + + ISC_TIMESTAMP aISCTimestamp; + isc_encode_timestamp(&aCTime, &aISCTimestamp); + + // As in previous function + aISCTimestamp.timestamp_time += rTimestamp.NanoSeconds / (1000000000 / ISC_TIME_SECONDS_PRECISION); + + setValue< ISC_TIMESTAMP >(nIndex, aISCTimestamp, SQL_TIMESTAMP); +} + + +// void OPreparedStatement::set +void OPreparedStatement::openBlobForWriting(isc_blob_handle& rBlobHandle, ISC_QUAD& rBlobId) +{ + ISC_STATUS aErr; + + aErr = isc_create_blob2(m_statusVector, + &m_pConnection->getDBHandle(), + &m_pConnection->getTransaction(), + &rBlobHandle, + &rBlobId, + 0, // Blob parameter buffer length + nullptr); // Blob parameter buffer handle + + if (aErr) + { + evaluateStatusVector(m_statusVector, + "setBlob failed on " + m_sSqlStatement, + *this); + assert(false); + } +} + +void OPreparedStatement::closeBlobAfterWriting(isc_blob_handle& rBlobHandle) +{ + ISC_STATUS aErr; + + aErr = isc_close_blob(m_statusVector, + &rBlobHandle); + if (aErr) + { + evaluateStatusVector(m_statusVector, + "isc_close_blob failed", + *this); + assert(false); + } +} + +void SAL_CALL OPreparedStatement::setClob(sal_Int32 nParameterIndex, const Reference< XClob >& xClob ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + +#if SAL_TYPES_SIZEOFPOINTER == 8 + isc_blob_handle aBlobHandle = 0; +#else + isc_blob_handle aBlobHandle = nullptr; +#endif + ISC_QUAD aBlobId; + + openBlobForWriting(aBlobHandle, aBlobId); + + + // Max segment size is 2^16 == SAL_MAX_UINT16 + // SAL_MAX_UINT16 / 4 is surely enough for UTF-8 + // TODO apply max segment size to character encoding + sal_Int64 nCharWritten = 1; // XClob is indexed from 1 + ISC_STATUS aErr = 0; + sal_Int64 nLen = xClob->length(); + while ( nLen > nCharWritten ) + { + sal_Int64 nCharRemain = nLen - nCharWritten; + constexpr sal_uInt16 MAX_SIZE = SAL_MAX_UINT16 / 4; + sal_uInt16 nWriteSize = std::min<sal_Int64>(nCharRemain, MAX_SIZE); + OString sData = OUStringToOString( + xClob->getSubString(nCharWritten, nWriteSize), + RTL_TEXTENCODING_UTF8); + aErr = isc_put_segment( m_statusVector, + &aBlobHandle, + sData.getLength(), + sData.getStr() ); + nCharWritten += nWriteSize; + + if (aErr) + break; + } + + // We need to make sure we close the Blob even if there are errors, hence evaluate + // errors after closing. + closeBlobAfterWriting(aBlobHandle); + + if (aErr) + { + evaluateStatusVector(m_statusVector, + "isc_put_segment failed", + *this); + assert(false); + } + + setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB); +} + +void OPreparedStatement::setClob( sal_Int32 nParameterIndex, const OUString& rStr ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nParameterIndex); + +#if SAL_TYPES_SIZEOFPOINTER == 8 + isc_blob_handle aBlobHandle = 0; +#else + isc_blob_handle aBlobHandle = nullptr; +#endif + ISC_QUAD aBlobId; + + openBlobForWriting(aBlobHandle, aBlobId); + + OString sData = OUStringToOString( + rStr, + RTL_TEXTENCODING_UTF8); + ISC_STATUS aErr = isc_put_segment( m_statusVector, + &aBlobHandle, + sData.getLength(), + sData.getStr() ); + + // We need to make sure we close the Blob even if there are errors, hence evaluate + // errors after closing. + closeBlobAfterWriting(aBlobHandle); + + if (aErr) + { + evaluateStatusVector(m_statusVector, + "isc_put_segment failed", + *this); + assert(false); + } + + setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB); +} + +void SAL_CALL OPreparedStatement::setBlob(sal_Int32 nParameterIndex, + const Reference< XBlob >& xBlob) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nParameterIndex); + +#if SAL_TYPES_SIZEOFPOINTER == 8 + isc_blob_handle aBlobHandle = 0; +#else + isc_blob_handle aBlobHandle = nullptr; +#endif + ISC_QUAD aBlobId; + + openBlobForWriting(aBlobHandle, aBlobId); + + ISC_STATUS aErr = 0; + const sal_Int64 nBlobLen = xBlob->length(); + if (nBlobLen > 0) + { + // Max write size is 0xFFFF == SAL_MAX_UINT16 + sal_uInt64 nDataWritten = 0; + while (sal::static_int_cast<sal_uInt64>(nBlobLen) > nDataWritten) + { + sal_uInt64 nDataRemaining = nBlobLen - nDataWritten; + sal_uInt16 nWriteSize = std::min(nDataRemaining, sal_uInt64(SAL_MAX_UINT16)); + aErr = isc_put_segment(m_statusVector, + &aBlobHandle, + nWriteSize, + reinterpret_cast<const char*>(xBlob->getBytes(nDataWritten, nWriteSize).getConstArray())); + nDataWritten += nWriteSize; + + if (aErr) + break; + } + } + + // We need to make sure we close the Blob even if there are errors, hence evaluate + // errors after closing. + closeBlobAfterWriting(aBlobHandle); + + if (aErr) + { + evaluateStatusVector(m_statusVector, + "isc_put_segment failed", + *this); + assert(false); + } + + setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB); +} + + +void SAL_CALL OPreparedStatement::setArray( sal_Int32 nIndex, const Reference< XArray >& ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nIndex); +} + + +void SAL_CALL OPreparedStatement::setRef( sal_Int32 nIndex, const Reference< XRef >& ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nIndex); +} + + +void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) +{ + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + ensurePrepared(); + + checkParameterIndex(parameterIndex); + setParameterNull(parameterIndex, false); + + XSQLVAR* pVar = m_pInSqlda->sqlvar + (parameterIndex - 1); + int dType = (pVar->sqltype & ~1); // drop null flag + + if(sqlType == DataType::DECIMAL || sqlType == DataType::NUMERIC) + { + double dbValue =0.0; + OUString sValue; + if( x >>= dbValue ) + { + // truncate and round to 'scale' number of decimal places + sValue = OUString::number( std::floor((dbValue * pow10Integer(scale)) + .5) / pow10Integer(scale) ); + } + else + { + x >>= sValue; + } + + // fill in the number with nulls in fractional part. + // We need this because e.g. 0.450 != 0.045 despite + // their scale is equal + OUStringBuffer sBuffer(15); + sBuffer.append(sValue); + if(sValue.indexOf('.') != -1) // there is a dot + { + for(sal_Int32 i=sValue.copy(sValue.indexOf('.')+1).getLength(); i<scale;i++) + { + sBuffer.append('0'); + } + } + else + { + for (sal_Int32 i=0; i<scale; i++) + { + sBuffer.append('0'); + } + } + + sValue = sBuffer.makeStringAndClear(); + switch(dType) + { + case SQL_SHORT: + setValue< sal_Int16 >(parameterIndex, + static_cast<sal_Int16>( toNumericWithoutDecimalPlace(sValue) ), + dType); + break; + case SQL_LONG: + case SQL_DOUBLE: + setValue< sal_Int32 >(parameterIndex, + static_cast<sal_Int32>( toNumericWithoutDecimalPlace(sValue) ), + dType); + break; + case SQL_INT64: + setValue< sal_Int64 >(parameterIndex, + toNumericWithoutDecimalPlace(sValue), + dType); + break; + default: + SAL_WARN("connectivity.firebird", + "No Firebird sql type found for numeric or decimal types"); + ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); + } + } + else + { + ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); + } + +} + + +void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 nIndex, sal_Int32, const OUString& ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nIndex); +} + + +void SAL_CALL OPreparedStatement::setObject( sal_Int32 nIndex, const Any& ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nIndex); +} + +void SAL_CALL OPreparedStatement::setBytes(sal_Int32 nParameterIndex, + const Sequence< sal_Int8 >& xBytes) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nParameterIndex); + + XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1); + int dType = (pVar->sqltype & ~1); // drop flag bit for now + + if( dType == SQL_BLOB ) + { +#if SAL_TYPES_SIZEOFPOINTER == 8 + isc_blob_handle aBlobHandle = 0; +#else + isc_blob_handle aBlobHandle = nullptr; +#endif + ISC_QUAD aBlobId; + + openBlobForWriting(aBlobHandle, aBlobId); + + ISC_STATUS aErr = 0; + const sal_Int32 nBytesLen = xBytes.getLength(); + if (nBytesLen > 0) + { + // Max write size is 0xFFFF == SAL_MAX_UINT16 + sal_uInt32 nDataWritten = 0; + while (sal::static_int_cast<sal_uInt32>(nBytesLen) > nDataWritten) + { + sal_uInt32 nDataRemaining = nBytesLen - nDataWritten; + sal_uInt16 nWriteSize = std::min(nDataRemaining, sal_uInt32(SAL_MAX_UINT16)); + aErr = isc_put_segment(m_statusVector, + &aBlobHandle, + nWriteSize, + reinterpret_cast<const char*>(xBytes.getConstArray()) + nDataWritten); + nDataWritten += nWriteSize; + + if (aErr) + break; + } + } + + // We need to make sure we close the Blob even if there are errors, hence evaluate + // errors after closing. + closeBlobAfterWriting(aBlobHandle); + + if (aErr) + { + evaluateStatusVector(m_statusVector, + "isc_put_segment failed", + *this); + assert(false); + } + + setValue< ISC_QUAD >(nParameterIndex, aBlobId, SQL_BLOB); + } + else if( dType == SQL_VARYING ) + { + setParameterNull(nParameterIndex, false); + const sal_Int32 nMaxSize = 0xFFFF; + Sequence<sal_Int8> xBytesCopy(xBytes); + if (xBytesCopy.getLength() > nMaxSize) + { + xBytesCopy.realloc( nMaxSize ); + } + const auto nSize = xBytesCopy.getLength(); + // 8000 corresponds to value from lcl_addDefaultParameters + // in dbaccess/source/filter/hsqldb/createparser.cxx + if (nSize > 8000) + { + free(pVar->sqldata); + pVar->sqldata = static_cast<char *>(malloc(sizeof(char) * nSize + 2)); + } + // First 2 bytes indicate string size + memcpy(pVar->sqldata, &nSize, 2); + // Actual data + memcpy(pVar->sqldata + 2, xBytesCopy.getConstArray(), nSize); + } + else if( dType == SQL_TEXT ) + { + setParameterNull(nParameterIndex, false); + memcpy(pVar->sqldata, xBytes.getConstArray(), xBytes.getLength() ); + // Fill remainder with spaces + memset(pVar->sqldata + xBytes.getLength(), 0, pVar->sqllen - xBytes.getLength()); + } + else + { + ::dbtools::throwSQLException( + "Incorrect type for setBytes", + ::dbtools::StandardSQLState::INVALID_SQL_DATA_TYPE, + *this); + } +} + + +void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 nIndex, const Reference< css::io::XInputStream >&, sal_Int32 ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nIndex); +} + + +void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 nIndex, const Reference< css::io::XInputStream >&, sal_Int32 ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + checkParameterIndex(nIndex); +} + + +void SAL_CALL OPreparedStatement::clearParameters( ) +{ +} + +// ---- Batch methods -- unsupported ----------------------------------------- +void SAL_CALL OPreparedStatement::clearBatch() +{ + // Unsupported +} + +void SAL_CALL OPreparedStatement::addBatch() +{ + // Unsupported by firebird +} + +Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch() +{ + // Unsupported by firebird + return Sequence< sal_Int32 >(); +} + +void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + switch(nHandle) + { + case PROPERTY_ID_RESULTSETCONCURRENCY: + break; + case PROPERTY_ID_RESULTSETTYPE: + break; + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_USEBOOKMARKS: + break; + default: + OStatementCommonBase::setFastPropertyValue_NoBroadcast(nHandle,rValue); + } +} + +void OPreparedStatement::checkParameterIndex(sal_Int32 nParameterIndex) +{ + ensurePrepared(); + if ((nParameterIndex == 0) || (nParameterIndex > m_pInSqlda->sqld)) + { + ::dbtools::throwSQLException( + "No column " + OUString::number(nParameterIndex), + ::dbtools::StandardSQLState::COLUMN_NOT_FOUND, + *this); + } +} + +void OPreparedStatement::setParameterNull(sal_Int32 nParameterIndex, + bool bSetNull) +{ + XSQLVAR* pVar = m_pInSqlda->sqlvar + (nParameterIndex - 1); + if (bSetNull) + { + pVar->sqltype |= 1; + *pVar->sqlind = -1; + } + else + *pVar->sqlind = 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/PreparedStatement.hxx b/connectivity/source/drivers/firebird/PreparedStatement.hxx new file mode 100644 index 000000000..e77201791 --- /dev/null +++ b/connectivity/source/drivers/firebird/PreparedStatement.hxx @@ -0,0 +1,156 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_PREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_PREPAREDSTATEMENT_HXX + +#include "StatementCommonBase.hxx" + +#include <cppuhelper/implbase5.hxx> + +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp> +#include <com/sun/star/io/XInputStream.hpp> + +#include <ibase.h> + +namespace connectivity +{ + namespace firebird + { + + class OBoundParam; + typedef ::cppu::ImplHelper5< css::sdbc::XPreparedStatement, + css::sdbc::XParameters, + css::sdbc::XPreparedBatchExecution, + css::sdbc::XResultSetMetaDataSupplier, + css::lang::XServiceInfo> OPreparedStatement_Base; + + class OPreparedStatement : public OStatementCommonBase, + public OPreparedStatement_Base + { + protected: + OUString m_sSqlStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData; + + XSQLDA* m_pOutSqlda; + XSQLDA* m_pInSqlda; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkParameterIndex(sal_Int32 nParameterIndex); + + /** + * Set a numeric value in the input SQLDA. If the destination + * parameter is not of nType then an Exception will be thrown. + * + * @throws css::sdbc::SQLException + * @throws css::uno::RuntimeException + */ + template <typename T> void setValue(sal_Int32 nIndex, const T& nValue, ISC_SHORT nType); + void setParameterNull(sal_Int32 nParameterIndex, bool bSetNull = true); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void ensurePrepared(); + /** + * Assumes that all necessary mutexes have been taken. + */ + void openBlobForWriting(isc_blob_handle& rBlobHandle, ISC_QUAD& rBlobId); + /** + * Assumes that all necessary mutexes have been taken. + */ + void closeBlobAfterWriting(isc_blob_handle& rBlobHandle); + void setClob(sal_Int32 nParamIndex, const OUString& rStr); + + protected: + virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, + const css::uno::Any& rValue) override; + virtual ~OPreparedStatement() override; + public: + DECLARE_SERVICE_INFO(); + // a constructor, which is required for returning objects: + OPreparedStatement( Connection* _pConnection, + const OUString& sql); + + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + executeQuery() override; + virtual sal_Int32 SAL_CALL + executeUpdate() override; + virtual sal_Bool SAL_CALL + execute() override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL + getConnection() override; + + // XParameters + virtual void SAL_CALL setNull(sal_Int32 nIndex, sal_Int32 nValue) override; + virtual void SAL_CALL setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 nIndex, sal_Bool nValue) override; + virtual void SAL_CALL setByte(sal_Int32 nIndex, sal_Int8 nValue) override; + virtual void SAL_CALL setShort(sal_Int32 nIndex, sal_Int16 nValue) override; + virtual void SAL_CALL setInt(sal_Int32 nIndex, sal_Int32 nValue) override; + virtual void SAL_CALL setLong(sal_Int32 nIndex, sal_Int64 nValue) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + + // XPreparedBatchExecution -- UNSUPPORTED by firebird + virtual void SAL_CALL + addBatch() override; + virtual void SAL_CALL + clearBatch() override; + virtual css::uno::Sequence< sal_Int32 > SAL_CALL + executeBatch() override; + + // XCloseable + virtual void SAL_CALL close() override; + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_PREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/ResultSet.cxx b/connectivity/source/drivers/firebird/ResultSet.cxx new file mode 100644 index 000000000..7ae77c607 --- /dev/null +++ b/connectivity/source/drivers/firebird/ResultSet.cxx @@ -0,0 +1,909 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 "ResultSet.hxx" +#include "ResultSetMetaData.hxx" +#include "Util.hxx" + +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/dbexception.hxx> +#include <propertyids.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <TConnection.hxx> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +using namespace ::comphelper; +using namespace ::connectivity; +using namespace ::connectivity::firebird; +using namespace ::cppu; +using namespace ::dbtools; +using namespace ::osl; + +using namespace ::com::sun::star; +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::sdbcx; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::util; + +OResultSet::OResultSet(Connection* pConnection, + ::osl::Mutex& rMutex, + const uno::Reference< XInterface >& xStatement, + isc_stmt_handle aStatementHandle, + XSQLDA* pSqlda ) + : OResultSet_BASE(rMutex) + , OPropertyContainer(OResultSet_BASE::rBHelper) + , m_bIsBookmarkable(false) + , m_nFetchSize(1) + , m_nResultSetType(css::sdbc::ResultSetType::FORWARD_ONLY) + , m_nFetchDirection(css::sdbc::FetchDirection::FORWARD) + , m_nResultSetConcurrency(css::sdbc::ResultSetConcurrency::READ_ONLY) + , m_pConnection(pConnection) + , m_rMutex(rMutex) + , m_xStatement(xStatement) + , m_pSqlda(pSqlda) + , m_statementHandle(aStatementHandle) + , m_bWasNull(false) + , m_currentRow(0) + , m_bIsAfterLastRow(false) + , m_fieldCount(pSqlda? pSqlda->sqld : 0) +{ + SAL_INFO("connectivity.firebird", "OResultSet()."); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), + PROPERTY_ID_ISBOOKMARKABLE, + PropertyAttribute::READONLY, + &m_bIsBookmarkable, + cppu::UnoType<decltype(m_bIsBookmarkable)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + PropertyAttribute::READONLY, + &m_nFetchSize, + cppu::UnoType<decltype(m_nFetchSize)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + PropertyAttribute::READONLY, + &m_nResultSetType, + cppu::UnoType<decltype(m_nResultSetType)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + PropertyAttribute::READONLY, + &m_nFetchDirection, + cppu::UnoType<decltype(m_nFetchDirection)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + PropertyAttribute::READONLY, + &m_nResultSetConcurrency, + cppu::UnoType<decltype(m_nResultSetConcurrency)>::get()); + + if (!pSqlda) + return; // TODO: what? + +} + +OResultSet::~OResultSet() +{ +} + +// ---- XResultSet -- Row retrieval methods ------------------------------------ +sal_Int32 SAL_CALL OResultSet::getRow() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_currentRow; +} + +sal_Bool SAL_CALL OResultSet::next() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_currentRow++; + + ISC_STATUS fetchStat = isc_dsql_fetch(m_statusVector, + &m_statementHandle, + 1, + m_pSqlda); + if (fetchStat == 0) // SUCCESSFUL + { + return true; + } + else if (fetchStat == 100) // END OF DATASET + { + m_bIsAfterLastRow = true; + return false; + } + else + { + SAL_WARN("connectivity.firebird", "Error when fetching data"); + // Throws sql exception as appropriate + evaluateStatusVector(m_statusVector, "isc_dsql_fetch", *this); + return false; + } +} + +sal_Bool SAL_CALL OResultSet::previous() +{ + ::dbtools::throwFunctionNotSupportedSQLException("previous not supported in firebird", + *this); + return false; +} + +sal_Bool SAL_CALL OResultSet::isLast() +{ + ::dbtools::throwFunctionNotSupportedSQLException("isLast not supported in firebird", + *this); + return false; +} + +sal_Bool SAL_CALL OResultSet::isBeforeFirst() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_currentRow == 0; +} + +sal_Bool SAL_CALL OResultSet::isAfterLast() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_bIsAfterLastRow; +} + +sal_Bool SAL_CALL OResultSet::isFirst() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_currentRow == 1 && !m_bIsAfterLastRow; +} + +void SAL_CALL OResultSet::beforeFirst() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (m_currentRow != 0) + ::dbtools::throwFunctionNotSupportedSQLException("beforeFirst not supported in firebird", + *this); +} + +void SAL_CALL OResultSet::afterLast() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (!m_bIsAfterLastRow) + ::dbtools::throwFunctionNotSupportedSQLException("afterLast not supported in firebird", + *this); +} + +sal_Bool SAL_CALL OResultSet::first() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (m_currentRow == 0) + { + return next(); + } + else if (m_currentRow == 1 && !m_bIsAfterLastRow) + { + return true; + } + else + { + ::dbtools::throwFunctionNotSupportedSQLException("first not supported in firebird", + *this); + return false; + } +} + +sal_Bool SAL_CALL OResultSet::last() +{ + // We need to iterate past the last row to know when we've passed the last + // row, hence we can't actually move to last. + ::dbtools::throwFunctionNotSupportedSQLException("last not supported in firebird", + *this); + return false; +} + +sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 aRow) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (aRow > m_currentRow) + { + sal_Int32 aIterations = aRow - m_currentRow; + return relative(aIterations); + } + else + { + ::dbtools::throwFunctionNotSupportedSQLException("absolute not supported in firebird", + *this); + return false; + } +} + +sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (row > 0) + { + while (row--) + { + if (!next()) + return false; + } + return true; + } + else + { + ::dbtools::throwFunctionNotSupportedSQLException("relative not supported in firebird", + *this); + return false; + } +} + +void OResultSet::checkColumnIndex(sal_Int32 nIndex) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if( nIndex < 1 || nIndex > m_fieldCount ) + { + ::dbtools::throwSQLException( + "No column " + OUString::number(nIndex), + ::dbtools::StandardSQLState::COLUMN_NOT_FOUND, + *this); + } +} + +void OResultSet::checkRowIndex() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if((m_currentRow < 1) || m_bIsAfterLastRow) + { + ::dbtools::throwSQLException( + "Invalid Row", + ::dbtools::StandardSQLState::INVALID_CURSOR_POSITION, + *this); + } +} + +Any SAL_CALL OResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType); +} + + Sequence< Type > SAL_CALL OResultSet::getTypes() +{ + return concatSequences(OPropertySetHelper::getTypes(), OResultSet_BASE::getTypes()); +} +// ---- XColumnLocate --------------------------------------------------------- +sal_Int32 SAL_CALL OResultSet::findColumn(const OUString& rColumnName) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + uno::Reference< XResultSetMetaData > xMeta = getMetaData(); + sal_Int32 nLen = xMeta->getColumnCount(); + sal_Int32 i; + + for(i = 1; i<=nLen; ++i) + { + // We assume case sensitive, otherwise you'd have to test + // xMeta->isCaseSensitive and use qualsIgnoreAsciiCase as needed. + if (rColumnName == xMeta->getColumnName(i)) + return i; + } + + ::dbtools::throwInvalidColumnException(rColumnName, *this); + assert(false); + return 0; // Never reached +} + +uno::Reference< XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 ) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return nullptr; +} + +uno::Reference< XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 ) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return nullptr; +} + +// ---- Internal Utilities --------------------------------------------------- +bool OResultSet::isNull(const sal_Int32 nColumnIndex) +{ + assert(nColumnIndex <= m_fieldCount); + XSQLVAR* pVar = m_pSqlda->sqlvar; + + if (pVar[nColumnIndex-1].sqltype & 1) // Indicates column may contain null + { + if (*pVar[nColumnIndex-1].sqlind == -1) + return true; + } + return false; +} + +template <typename T> +OUString OResultSet::makeNumericString(const sal_Int32 nColumnIndex) +{ + // minus because firebird stores scale as a negative number + int nDecimalCount = -(m_pSqlda->sqlvar[nColumnIndex-1].sqlscale); + if(nDecimalCount < 0) + { + // scale should be always positive + assert(false); + return OUString(); + } + + OUStringBuffer sRetBuffer; + T nAllDigits = *reinterpret_cast<T*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + sal_Int64 nDecimalCountExp = pow10Integer(nDecimalCount); + + if(nAllDigits < 0) + { + sRetBuffer.append('-'); + nAllDigits = -nAllDigits; // abs + } + + sRetBuffer.append(static_cast<sal_Int64>(nAllDigits / nDecimalCountExp) ); + if( nDecimalCount > 0) + { + sRetBuffer.append('.'); + + sal_Int64 nFractionalPart = nAllDigits % nDecimalCountExp; + + int iCount = 0; // digit count + sal_Int64 nFracTemp = nFractionalPart; + while(nFracTemp>0) + { + nFracTemp /= 10; + iCount++; + } + + int nMissingNulls = nDecimalCount - iCount; + + // append nulls after dot and before nFractionalPart + for(int i=0; i<nMissingNulls; i++) + { + sRetBuffer.append('0'); + } + + // the rest + sRetBuffer.append(nFractionalPart); + } + + return sRetBuffer.makeStringAndClear(); +} + +template <typename T> +T OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType) +{ + m_bWasNull = isNull(nColumnIndex); + if (m_bWasNull) + return T(); + + if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == nType) + return *reinterpret_cast<T*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + else + return retrieveValue< ORowSetValue >(nColumnIndex, 0); +} + +template <> +ORowSetValue OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) +{ + // See http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/Using_the_getXXX_Methods + // (bottom of page) for a chart of possible conversions, we should allow all + // of these -- Blob/Clob will probably need some specialist handling especially + // w.r.t. to generating Strings for them. + // + // Basically we just have to map to the correct direct request and + // ORowSetValue does the rest for us here. + int nSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype; + + // TODO Firebird 3.0 does not set subtype (i.e. set to 0) for computed numeric/decimal value. + // It may change in the future. + // Imply numeric data type when subtype is 0 and scale is negative + if( nSqlSubType == 0 && m_pSqlda->sqlvar[nColumnIndex-1].sqlscale < 0 ) + nSqlSubType = 1; + + switch (m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) + { + case SQL_TEXT: + case SQL_VARYING: + return getString(nColumnIndex); + case SQL_SHORT: + if(nSqlSubType == 1 || nSqlSubType == 2) //numeric or decimal + return getString(nColumnIndex); + return getShort(nColumnIndex); + case SQL_LONG: + if(nSqlSubType == 1 || nSqlSubType == 2) //numeric or decimal + return getString(nColumnIndex); + return getInt(nColumnIndex); + case SQL_FLOAT: + return getFloat(nColumnIndex); + case SQL_DOUBLE: + if(nSqlSubType == 1 || nSqlSubType == 2) //numeric or decimal + return getString(nColumnIndex); + return getDouble(nColumnIndex); + case SQL_D_FLOAT: + return getFloat(nColumnIndex); + case SQL_TIMESTAMP: + return getTimestamp(nColumnIndex); + case SQL_TYPE_TIME: + return getTime(nColumnIndex); + case SQL_TYPE_DATE: + return getDate(nColumnIndex); + case SQL_INT64: + if(nSqlSubType == 1 || nSqlSubType == 2) //numeric or decimal + return getString(nColumnIndex); + return getLong(nColumnIndex); + case SQL_BOOLEAN: + return ORowSetValue(bool(getBoolean(nColumnIndex))); + case SQL_BLOB: + case SQL_NULL: + case SQL_QUAD: + case SQL_ARRAY: + // TODO: these are all invalid conversions, so maybe we should + // throw an exception? + return ORowSetValue(); + default: + assert(false); + return ORowSetValue(); + } +} + +template <> +Date OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) +{ + if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TYPE_DATE) + { + ISC_DATE aISCDate = *reinterpret_cast<ISC_DATE*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + + struct tm aCTime; + isc_decode_sql_date(&aISCDate, &aCTime); + + return Date(aCTime.tm_mday, aCTime.tm_mon + 1, aCTime.tm_year + 1900); + } + else + { + return retrieveValue< ORowSetValue >(nColumnIndex, 0); + } +} + +template <> +Time OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) +{ + if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TYPE_TIME) + { + ISC_TIME aISCTime = *reinterpret_cast<ISC_TIME*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + + struct tm aCTime; + isc_decode_sql_time(&aISCTime, &aCTime); + + // First field is nanoseconds. + // last field denotes UTC (true) or unknown (false) + // Here we "know" that ISC_TIME is simply in units of seconds/ISC_TIME_SECONDS_PRECISION + // with no other funkiness, so we can get the fractional seconds easily. + return Time((aISCTime % ISC_TIME_SECONDS_PRECISION) * (1000000000 / ISC_TIME_SECONDS_PRECISION), + aCTime.tm_sec, aCTime.tm_min, aCTime.tm_hour, false); + } + else + { + return retrieveValue< ORowSetValue >(nColumnIndex, 0); + } +} + +template <> +DateTime OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) +{ + if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) == SQL_TIMESTAMP) + { + ISC_TIMESTAMP aISCTimestamp = *reinterpret_cast<ISC_TIMESTAMP*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + + struct tm aCTime; + isc_decode_timestamp(&aISCTimestamp, &aCTime); + + // Ditto here, see comment in previous function about ISC_TIME and ISC_TIME_SECONDS_PRECISION. + return DateTime((aISCTimestamp.timestamp_time % ISC_TIME_SECONDS_PRECISION) * (1000000000 / ISC_TIME_SECONDS_PRECISION), //nanoseconds + aCTime.tm_sec, + aCTime.tm_min, + aCTime.tm_hour, + aCTime.tm_mday, + aCTime.tm_mon + 1, // tm is from 0 to 11 + aCTime.tm_year + 1900, //tm_year is the years since 1900 + false); // denotes UTC (true), or unknown (false) + } + else + { + return retrieveValue< ORowSetValue >(nColumnIndex, 0); + } +} + +template <> +OUString OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT /*nType*/) +{ + // &~1 to remove the "can contain NULL" indicator + int aSqlType = m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1; + int aSqlSubType = m_pSqlda->sqlvar[nColumnIndex-1].sqlsubtype; + if (aSqlType == SQL_TEXT ) + { + return OUString(m_pSqlda->sqlvar[nColumnIndex-1].sqldata, + m_pSqlda->sqlvar[nColumnIndex-1].sqllen, + RTL_TEXTENCODING_UTF8); + } + else if (aSqlType == SQL_VARYING) + { + // First 2 bytes are a short containing the length of the string + // No idea if sqllen is still valid here? + sal_uInt16 aLength = *reinterpret_cast<sal_uInt16*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); + return OUString(m_pSqlda->sqlvar[nColumnIndex-1].sqldata + 2, + aLength, + RTL_TEXTENCODING_UTF8); + } + else if ((aSqlType == SQL_SHORT || aSqlType == SQL_LONG || + aSqlType == SQL_DOUBLE || aSqlType == SQL_INT64) + && (aSqlSubType == 1 || + aSqlSubType == 2 || + (aSqlSubType == 0 && m_pSqlda->sqlvar[nColumnIndex-1].sqlscale < 0) ) ) + { + // decimal and numeric types + switch(aSqlType) + { + case SQL_SHORT: + return makeNumericString<sal_Int16>(nColumnIndex); + case SQL_LONG: + return makeNumericString<sal_Int32>(nColumnIndex); + case SQL_DOUBLE: + // TODO FIXME 64 bits? + case SQL_INT64: + return makeNumericString<sal_Int64>(nColumnIndex); + default: + assert(false); + return OUString(); // never reached + } + } + else if(aSqlType == SQL_BLOB && aSqlSubType == static_cast<short>(BlobSubtype::Clob) ) + { + uno::Reference<XClob> xClob = getClob(nColumnIndex); + return xClob->getSubString( 0, xClob->length() ); + } + else + { + return retrieveValue< ORowSetValue >(nColumnIndex, 0); + } +} + +template <> +ISC_QUAD* OResultSet::retrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType) +{ + // TODO: this is probably wrong + if ((m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1) != nType) + throw SQLException(); // TODO: better exception (can't convert Blob) + + return reinterpret_cast<ISC_QUAD*>(m_pSqlda->sqlvar[nColumnIndex-1].sqldata); +} + +template <typename T> +T OResultSet::safelyRetrieveValue(const sal_Int32 nColumnIndex, const ISC_SHORT nType) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + checkColumnIndex(nColumnIndex); + checkRowIndex(); + + m_bWasNull = isNull(nColumnIndex); + if (m_bWasNull) + return T(); + + return retrieveValue< T >(nColumnIndex, nType); +} + +// ---- XRow ----------------------------------------------------------------- +sal_Bool SAL_CALL OResultSet::wasNull() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + +// ---- XRow: Simple Numerical types ------------------------------------------ +sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 nColumnIndex) +{ + return safelyRetrieveValue< bool >(nColumnIndex, SQL_BOOLEAN); +} + +sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 nColumnIndex) +{ + // Not a native firebird type hence we always have to convert. + return safelyRetrieveValue< ORowSetValue >(nColumnIndex); +} + +Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes(sal_Int32 nColumnIndex) +{ + // &~1 to remove the "can contain NULL" indicator + int aSqlType = m_pSqlda->sqlvar[nColumnIndex-1].sqltype & ~1; + if ( aSqlType == SQL_BLOB ) + { + Reference< XBlob> xBlob = getBlob(nColumnIndex); + if (xBlob.is()) + { + const sal_Int64 aBlobLength = xBlob->length(); + if (aBlobLength > SAL_MAX_INT32) + { + SAL_WARN("connectivity.firebird", "getBytes can't return " << aBlobLength << " bytes but only max " << SAL_MAX_INT32); + return xBlob->getBytes(1, SAL_MAX_INT32); + } + return xBlob->getBytes(1, static_cast<sal_Int32>(aBlobLength)); + } + else + return Sequence< sal_Int8 >(); + } + // TODO implement SQL_VARYING and SQL_TEXT + // as it's the counterpart as OPreparedStatement::setBytes + else + { + return Sequence< sal_Int8 >(); // TODO: implement + } +} + +sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 columnIndex) +{ + return safelyRetrieveValue< sal_Int16 >(columnIndex, SQL_SHORT); +} + +sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 columnIndex) +{ + return safelyRetrieveValue< sal_Int32 >(columnIndex, SQL_LONG); +} + +sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 columnIndex) +{ + return safelyRetrieveValue< sal_Int64 >(columnIndex, SQL_INT64); +} + +float SAL_CALL OResultSet::getFloat(sal_Int32 columnIndex) +{ + return safelyRetrieveValue< float >(columnIndex, SQL_FLOAT); +} + +double SAL_CALL OResultSet::getDouble(sal_Int32 columnIndex) +{ + return safelyRetrieveValue< double >(columnIndex, SQL_DOUBLE); +} + +// ---- XRow: More complex types ---------------------------------------------- +OUString SAL_CALL OResultSet::getString(sal_Int32 nIndex) +{ + return safelyRetrieveValue< OUString >(nIndex); +} + +Date SAL_CALL OResultSet::getDate(sal_Int32 nIndex) +{ + return safelyRetrieveValue< Date >(nIndex, SQL_TYPE_DATE); +} + +Time SAL_CALL OResultSet::getTime(sal_Int32 nIndex) +{ + return safelyRetrieveValue< css::util::Time >(nIndex, SQL_TYPE_TIME); +} + +DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 nIndex) +{ + return safelyRetrieveValue< DateTime >(nIndex, SQL_TIMESTAMP); +} + + +uno::Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( ) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(m_pConnection + , m_pSqlda); + return m_xMetaData; +} + +uno::Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 ) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return nullptr; +} + + +uno::Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + int aSqlSubType = m_pSqlda->sqlvar[columnIndex-1].sqlsubtype; + + SAL_WARN_IF(aSqlSubType != 1, + "connectivity.firebird", "wrong subtype, not a textual blob"); + + ISC_QUAD* pBlobID = safelyRetrieveValue< ISC_QUAD* >(columnIndex, SQL_BLOB); + if (!pBlobID) + return nullptr; + return m_pConnection->createClob(pBlobID); +} + +uno::Reference< XBlob > SAL_CALL OResultSet::getBlob(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // TODO: CLOB etc. should be valid here too, but we probably want some more + // cleverness around this. + ISC_QUAD* pBlobID = safelyRetrieveValue< ISC_QUAD* >(columnIndex, SQL_BLOB); + if (!pBlobID) + return nullptr; + return m_pConnection->createBlob(pBlobID); +} + + +uno::Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 ) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return nullptr; +} + + +Any SAL_CALL OResultSet::getObject( sal_Int32, const uno::Reference< css::container::XNameAccess >& ) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return Any(); +} + + +void SAL_CALL OResultSet::close() +{ + SAL_INFO("connectivity.firebird", "close()."); + + { + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + } + dispose(); +} + + +uno::Reference< XInterface > SAL_CALL OResultSet::getStatement() +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_xStatement; +} +//----- XResultSet: unsupported change detection methods --------------------- +sal_Bool SAL_CALL OResultSet::rowDeleted() +{ + ::dbtools::throwFunctionNotSupportedSQLException("rowDeleted not supported in firebird", + *this); + return false; +} +sal_Bool SAL_CALL OResultSet::rowInserted() +{ + ::dbtools::throwFunctionNotSupportedSQLException("rowInserted not supported in firebird", + *this); + return false; +} + +sal_Bool SAL_CALL OResultSet::rowUpdated() +{ + ::dbtools::throwFunctionNotSupportedSQLException("rowUpdated not supported in firebird", + *this); + return false; +} + +void SAL_CALL OResultSet::refreshRow() +{ + ::dbtools::throwFunctionNotSupportedSQLException("refreshRow not supported in firebird", + *this); +} + + +void SAL_CALL OResultSet::cancel( ) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + +} + +//----- OIdPropertyArrayUsageHelper ------------------------------------------ +IPropertyArrayHelper* OResultSet::createArrayHelper() const +{ + Sequence< Property > aProperties; + describeProperties(aProperties); + return new ::cppu::OPropertyArrayHelper(aProperties); +} + +IPropertyArrayHelper & OResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +void SAL_CALL OResultSet::acquire() throw() +{ + OResultSet_BASE::acquire(); +} + +void SAL_CALL OResultSet::release() throw() +{ + OResultSet_BASE::release(); +} + +uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +// ---- XServiceInfo ----------------------------------------------------------- +OUString SAL_CALL OResultSet::getImplementationName() +{ + return "com.sun.star.sdbcx.firebird.ResultSet"; +} + +Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames() +{ + return {"com.sun.star.sdbc.ResultSet","com.sun.star.sdbcx.ResultSet"}; +} + +sal_Bool SAL_CALL OResultSet::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/ResultSet.hxx b/connectivity/source/drivers/firebird/ResultSet.hxx new file mode 100644 index 000000000..dc1a611fe --- /dev/null +++ b/connectivity/source/drivers/firebird/ResultSet.hxx @@ -0,0 +1,220 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_RESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_RESULTSET_HXX + +#include "Connection.hxx" + +#include <ibase.h> + +#include <connectivity/FValue.hxx> +#include <cppuhelper/compbase.hxx> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/propertycontainer.hxx> + +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> + +namespace connectivity +{ + namespace firebird + { + /* + ** OResultSet + */ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate, + css::lang::XServiceInfo> OResultSet_BASE; + + /** + * This ResultSet does not deal with the management of the SQLDA + * it is supplied with. The owner must mange its SQLDA appropriately + * and ensure that the ResultSet is destroyed before disposing of the + * SQLDA. + */ + class OResultSet: public OResultSet_BASE, + public ::comphelper::OPropertyContainer, + public ::comphelper::OPropertyArrayUsageHelper<OResultSet> + { + private: + bool m_bIsBookmarkable; + sal_Int32 m_nFetchSize; + sal_Int32 m_nResultSetType; + sal_Int32 m_nFetchDirection; + sal_Int32 m_nResultSetConcurrency; + + protected: + // Connection kept alive by m_xStatement + Connection* m_pConnection; + ::osl::Mutex& m_rMutex; + const css::uno::Reference< css::uno::XInterface >& m_xStatement; + + css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData; + + XSQLDA* m_pSqlda; + isc_stmt_handle m_statementHandle; + + bool m_bWasNull; + // Row numbering starts with 0 for "in front of first row" + sal_Int32 m_currentRow; + bool m_bIsAfterLastRow; + + const sal_Int32 m_fieldCount; + ISC_STATUS_ARRAY m_statusVector; + + bool isNull(const sal_Int32 nColumnIndex); + + template <typename T> OUString makeNumericString( + const sal_Int32 nColumnIndex); + + template <typename T> T retrieveValue(const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + + template <typename T> T safelyRetrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType = 0); + + // OIdPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex( sal_Int32 index ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkRowIndex(); + + // you can't delete objects of this type + virtual ~OResultSet() override; + public: + DECLARE_SERVICE_INFO(); + + OResultSet(Connection* pConnection, + ::osl::Mutex& rMutex, + const css::uno::Reference< css::uno::XInterface >& xStatement, + isc_stmt_handle aStatementHandle, + XSQLDA* aSqlda + ); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type& rType) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn(const OUString& columnName) override; + + }; + + // Specialisations have to be in the namespace and can't be within the class. + template <> css::util::Date + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> ::connectivity::ORowSetValue + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> css::util::Time + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> css::util::DateTime + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> ISC_QUAD* + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> OUString + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + template <> ISC_QUAD* + OResultSet::retrieveValue( + const sal_Int32 nColumnIndex, + const ISC_SHORT nType); + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_RESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/ResultSetMetaData.cxx b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx new file mode 100644 index 000000000..d21115029 --- /dev/null +++ b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx @@ -0,0 +1,296 @@ +/* -*- 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 "ResultSetMetaData.hxx" +#include "Util.hxx" + +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/DataType.hpp> + +#include <sal/log.hxx> + +using namespace connectivity::firebird; + +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; +using namespace com::sun::star::uno; + +OResultSetMetaData::~OResultSetMetaData() +{ +} + +OUString OResultSetMetaData::getCharacterSet( sal_Int32 nIndex ) +{ + OUString sTable = getTableName( nIndex ); + if( !sTable.isEmpty() ) + { + OUString sColumnName = getColumnName( nIndex ); + + OUString sSql = "SELECT charset.RDB$CHARACTER_SET_NAME " + "FROM RDB$CHARACTER_SETS charset " + "JOIN RDB$FIELDS fields " + "ON (fields.RDB$CHARACTER_SET_ID = charset.RDB$CHARACTER_SET_ID) " + "JOIN RDB$RELATION_FIELDS relfields " + "ON (fields.RDB$FIELD_NAME = relfields.RDB$FIELD_SOURCE) " + "WHERE relfields.RDB$RELATION_NAME = '" + + escapeWith(sTable, '\'', '\'') + "' AND " + "relfields.RDB$FIELD_NAME = '"+ escapeWith(sColumnName, '\'', '\'') +"'"; + + Reference<XStatement> xStmt= m_pConnection->createStatement(); + + Reference<XResultSet> xRes = + xStmt->executeQuery(sSql); + Reference<XRow> xRow ( xRes, UNO_QUERY); + if(xRes->next()) + { + OUString sCharset = xRow->getString(1).trim(); + return sCharset; + } + } + return OUString(); + + +} + +void OResultSetMetaData::verifyValidColumn(sal_Int32 column) +{ + if (column>getColumnCount() || column < 1) + throw SQLException("Invalid column specified", *this, OUString(), 0, Any()); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount() +{ + return m_pSqlda->sqld; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + verifyValidColumn(column); + return 32; // Hard limit for firebird +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnType(sal_Int32 column) +{ + verifyValidColumn(column); + + short aType = m_pSqlda->sqlvar[column-1].sqltype & ~1; + OUString sCharset; + + // do not query the character set unnecessarily + if(aType == SQL_TEXT || aType == SQL_VARYING) + { + sCharset = getCharacterSet(column); + } + + ColumnTypeInfo aInfo( m_pSqlda->sqlvar[column-1].sqltype, + m_pSqlda->sqlvar[column-1].sqlsubtype, + -(m_pSqlda->sqlvar[column-1].sqlscale), + sCharset ); + + return aInfo.getSdbcType(); +} + +sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32) +{ + // Firebird is generally case sensitive when using quoted identifiers. + // IF THIS CHANGES make ResultSet::findColumn to be case-insensitive as needed. + // Generally names that are entirely UPPERCASE are case insensitive, however + // there remains some ambiguity if there is another mixed-case-named column + // of the same name. For safety always assume case insensitive. + return true; +} + +OUString SAL_CALL OResultSetMetaData::getSchemaName(sal_Int32) +{ + return OUString(); // Schemas supported by firebird +} + +OUString SAL_CALL OResultSetMetaData::getColumnName(sal_Int32 column) +{ + verifyValidColumn(column); + OUString sRet(m_pSqlda->sqlvar[column-1].sqlname, + m_pSqlda->sqlvar[column-1].sqlname_length, + RTL_TEXTENCODING_UTF8); + sanitizeIdentifier(sRet); + return sRet; +} + +OUString SAL_CALL OResultSetMetaData::getTableName(sal_Int32 column) +{ + verifyValidColumn(column); + return OUString(m_pSqlda->sqlvar[column-1].relname, + m_pSqlda->sqlvar[column-1].relname_length, + RTL_TEXTENCODING_UTF8); +} + +OUString SAL_CALL OResultSetMetaData::getCatalogName(sal_Int32) +{ + return OUString(); // Catalogs not supported by firebird +} + +OUString SAL_CALL OResultSetMetaData::getColumnTypeName(sal_Int32 column) +{ + verifyValidColumn(column); + + ColumnTypeInfo aInfo( m_pSqlda->sqlvar[column-1].sqltype, + m_pSqlda->sqlvar[column-1].sqlsubtype, + -(m_pSqlda->sqlvar[column-1].sqlscale) ); + + return aInfo.getColumnTypeName(); +} + +OUString SAL_CALL OResultSetMetaData::getColumnLabel(sal_Int32 column) +{ + // aliasname + verifyValidColumn(column); + OUString sRet(m_pSqlda->sqlvar[column-1].aliasname, + m_pSqlda->sqlvar[column-1].aliasname_length, + RTL_TEXTENCODING_UTF8); + sanitizeIdentifier(sRet); + return sRet; +} + +OUString SAL_CALL OResultSetMetaData::getColumnServiceName(sal_Int32) +{ + // TODO: implement + return OUString(); +} + +sal_Bool SAL_CALL OResultSetMetaData::isCurrency(sal_Int32) +{ + return false; +} + +sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement(sal_Int32 column) +{ + OUString sTable = getTableName(column); + if( !sTable.isEmpty() ) + { + OUString sColumnName = getColumnName( column ); + + OUString sSql = "SELECT RDB$IDENTITY_TYPE FROM RDB$RELATION_FIELDS " + "WHERE RDB$RELATION_NAME = '" + + escapeWith(sTable, '\'', '\'') + "' AND " + "RDB$FIELD_NAME = '"+ escapeWith(sColumnName, '\'', '\'') +"'"; + + Reference<XStatement> xStmt =m_pConnection ->createStatement(); + + Reference<XResultSet> xRes = + xStmt->executeQuery(sSql); + Reference<XRow> xRow ( xRes, UNO_QUERY); + if(xRes->next()) + { + int iType = xRow->getShort(1); + if(iType == 1) // IDENTITY + return true; + } + else + { + SAL_WARN("connectivity.firebird","Column '" + << sColumnName + << "' not found in database"); + + return false; + } + } + return false; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isSigned(sal_Int32) +{ + // Unsigned values aren't supported in firebird. + return true; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getPrecision(sal_Int32 column) +{ + sal_Int32 nType = getColumnType(column); + if( nType == DataType::NUMERIC || nType == DataType::DECIMAL ) + { + OUString sColumnName = getColumnName( column ); + + // RDB$FIELD_SOURCE is a unique name of column per database + OUString sSql = "SELECT RDB$FIELD_PRECISION FROM RDB$FIELDS " + " INNER JOIN RDB$RELATION_FIELDS " + " ON RDB$RELATION_FIELDS.RDB$FIELD_SOURCE = RDB$FIELDS.RDB$FIELD_NAME " + "WHERE RDB$RELATION_FIELDS.RDB$RELATION_NAME = '" + + escapeWith(getTableName(column), '\'', '\'') + "' AND " + "RDB$RELATION_FIELDS.RDB$FIELD_NAME = '" + + escapeWith(sColumnName, '\'', '\'') +"'"; + Reference<XStatement> xStmt= m_pConnection->createStatement(); + + Reference<XResultSet> xRes = + xStmt->executeQuery(sSql); + Reference<XRow> xRow ( xRes, UNO_QUERY); + if(xRes->next()) + { + return static_cast<sal_Int32>(xRow->getShort(1)); + } + else + { + SAL_WARN("connectivity.firebird","Column '" + << sColumnName + << "' not found in database"); + return 0; + } + } + return 0; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getScale(sal_Int32 column) +{ + return -(m_pSqlda->sqlvar[column-1].sqlscale); // fb stores negative number +} + +sal_Int32 SAL_CALL OResultSetMetaData::isNullable(sal_Int32 column) +{ + if (m_pSqlda->sqlvar[column-1].sqltype & 1) + return ColumnValue::NULLABLE; + else + return ColumnValue::NO_NULLS; +} + +sal_Bool SAL_CALL OResultSetMetaData::isSearchable(sal_Int32) +{ + // TODO: Can the column be used as part of a where clause? Assume yes + return true; +} + +sal_Bool SAL_CALL OResultSetMetaData::isReadOnly(sal_Int32) +{ + return m_pConnection->isReadOnly(); // Readonly only available on db level +} + +sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable(sal_Int32) +{ + return !m_pConnection->isReadOnly(); +} + +sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 ) +{ + return !m_pConnection->isReadOnly(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/ResultSetMetaData.hxx b/connectivity/source/drivers/firebird/ResultSetMetaData.hxx new file mode 100644 index 000000000..1c6d1ca22 --- /dev/null +++ b/connectivity/source/drivers/firebird/ResultSetMetaData.hxx @@ -0,0 +1,84 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_RESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_RESULTSETMETADATA_HXX + +#include "Connection.hxx" + +#include <ibase.h> + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> + +namespace connectivity +{ + namespace firebird + { + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> + OResultSetMetaData_BASE; + + class OResultSetMetaData : public OResultSetMetaData_BASE + { + protected: + ::rtl::Reference<Connection> m_pConnection; + XSQLDA* m_pSqlda; + + virtual ~OResultSetMetaData() override; + + /// @throws css::sdbc::SQLException + void verifyValidColumn(sal_Int32 column); + OUString getCharacterSet(sal_Int32 nIndex); + public: + // a constructor, which is required for returning objects: + OResultSetMetaData(Connection* pConnection, + XSQLDA* pSqlda) + : m_pConnection(pConnection) + , m_pSqlda(pSqlda) + {} + + virtual sal_Int32 SAL_CALL getColumnCount() override; + virtual sal_Bool SAL_CALL isAutoIncrement(sal_Int32 column) override; + virtual sal_Bool SAL_CALL isCaseSensitive(sal_Int32 column) override; + virtual sal_Bool SAL_CALL isSearchable(sal_Int32 column) override; + virtual sal_Bool SAL_CALL isCurrency(sal_Int32 column) override; + virtual sal_Int32 SAL_CALL isNullable(sal_Int32 column) override; + virtual sal_Bool SAL_CALL isSigned(sal_Int32 column) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize(sal_Int32 column) override; + virtual OUString SAL_CALL getColumnLabel(sal_Int32 column) override; + virtual OUString SAL_CALL getColumnName(sal_Int32 column) override; + virtual OUString SAL_CALL getSchemaName(sal_Int32 column) override; + virtual sal_Int32 SAL_CALL getPrecision(sal_Int32 column) override; + virtual sal_Int32 SAL_CALL getScale(sal_Int32 column) override; + virtual OUString SAL_CALL getTableName(sal_Int32 column) override; + virtual OUString SAL_CALL getCatalogName(sal_Int32 column) override; + virtual sal_Int32 SAL_CALL getColumnType(sal_Int32 column) override; + virtual OUString SAL_CALL getColumnTypeName(sal_Int32 column) override; + virtual sal_Bool SAL_CALL isReadOnly(sal_Int32 column) override; + virtual sal_Bool SAL_CALL isWritable(sal_Int32 column) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable(sal_Int32 column) override; + virtual OUString SAL_CALL getColumnServiceName(sal_Int32 column) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_RESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Services.cxx b/connectivity/source/drivers/firebird/Services.cxx new file mode 100644 index 000000000..e72133692 --- /dev/null +++ b/connectivity/source/drivers/firebird/Services.cxx @@ -0,0 +1,109 @@ +/* -*- 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 "Driver.hxx" + +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <sal/types.h> + +using namespace connectivity::firebird; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* _pTemp + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* firebird_sdbc_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void*) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + FirebirdDriver::getImplementationName_Static(), + FirebirdDriver::getSupportedServiceNames_Static(), + FirebirdDriver_CreateInstance, ::cppu::createSingleFactory) + ; + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Statement.cxx b/connectivity/source/drivers/firebird/Statement.cxx new file mode 100644 index 000000000..418c66a7d --- /dev/null +++ b/connectivity/source/drivers/firebird/Statement.cxx @@ -0,0 +1,175 @@ +/* -*- 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 "Connection.hxx" +#include "ResultSet.hxx" +#include "Statement.hxx" +#include "Util.hxx" + +#include <comphelper/sequence.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <sal/log.hxx> + +using namespace connectivity::firebird; + +using namespace com::sun::star; +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +using namespace ::comphelper; +using namespace ::osl; +using namespace ::std; + +// ---- XBatchExecution - UNSUPPORTED ---------------------------------------- +void SAL_CALL OStatement::addBatch(const OUString&) +{ +} + +void SAL_CALL OStatement::clearBatch() +{ +} + +Sequence< sal_Int32 > SAL_CALL OStatement::executeBatch() +{ + return Sequence< sal_Int32 >(); +} + +IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.OStatement","com.sun.star.sdbc.Statement"); + +void SAL_CALL OStatement::acquire() throw() +{ + OStatementCommonBase::acquire(); +} + +void SAL_CALL OStatement::release() throw() +{ + OStatementCommonBase::release(); +} + +void OStatement::disposeResultSet() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + + OStatementCommonBase::disposeResultSet(); + + if (m_pSqlda) + { + freeSQLVAR(m_pSqlda); + free(m_pSqlda); + m_pSqlda = nullptr; + } +} + +// ---- XStatement ----------------------------------------------------------- +sal_Int32 SAL_CALL OStatement::executeUpdate(const OUString& sql) +{ + execute(sql); + return getStatementChangeCount(); +} + + +uno::Reference< XResultSet > SAL_CALL OStatement::executeQuery(const OUString& sql) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + + SAL_INFO("connectivity.firebird", "executeQuery(" << sql << ")"); + + ISC_STATUS aErr = 0; + + disposeResultSet(); + + prepareAndDescribeStatement(sql, + m_pSqlda); + + aErr = isc_dsql_execute(m_statusVector, + &m_pConnection->getTransaction(), + &m_aStatementHandle, + 1, + nullptr); + if (aErr) + SAL_WARN("connectivity.firebird", "isc_dsql_execute failed"); + + m_xResultSet = new OResultSet(m_pConnection.get(), + m_aMutex, + uno::Reference< XInterface >(*this), + m_aStatementHandle, + m_pSqlda ); + + // TODO: deal with cleanup + + evaluateStatusVector(m_statusVector, sql, *this); + + if (isDDLStatement()) + { + m_pConnection->commit(); + m_pConnection->notifyDatabaseModified(); + } + else if (getStatementChangeCount() > 0) + { + m_pConnection->notifyDatabaseModified(); + } + + return m_xResultSet; +} + +sal_Bool SAL_CALL OStatement::execute(const OUString& sql) +{ + uno::Reference< XResultSet > xResults = executeQuery(sql); + return xResults.is(); + // TODO: what if we have multiple results? +} + +uno::Reference< XConnection > SAL_CALL OStatement::getConnection() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + + return uno::Reference<XConnection>(m_pConnection.get()); +} + +Any SAL_CALL OStatement::queryInterface( const Type & rType ) +{ + Any aRet = OStatement_Base::queryInterface(rType); + if(!aRet.hasValue()) + aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this)); + if(!aRet.hasValue()) + aRet = OStatementCommonBase::queryInterface(rType); + return aRet; +} + +uno::Sequence< Type > SAL_CALL OStatement::getTypes() +{ + return concatSequences(OStatement_Base::getTypes(), + OStatementCommonBase::getTypes()); +} + +void SAL_CALL OStatement::disposing() +{ + disposeResultSet(); + close(); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Statement.hxx b/connectivity/source/drivers/firebird/Statement.hxx new file mode 100644 index 000000000..4c9168fd4 --- /dev/null +++ b/connectivity/source/drivers/firebird/Statement.hxx @@ -0,0 +1,89 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_STATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_STATEMENT_HXX + +#include "StatementCommonBase.hxx" + +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/sdbc/XBatchExecution.hpp> + +namespace connectivity +{ + namespace firebird + { + + typedef ::cppu::ImplHelper1< css::sdbc::XStatement > + OStatement_Base; + + class OStatement : public OStatementCommonBase, + public OStatement_Base, + public css::sdbc::XBatchExecution, + public css::lang::XServiceInfo + { + XSQLDA* m_pSqlda; + protected: + virtual ~OStatement() override {} + + public: + // a constructor, which is required for returning objects: + explicit OStatement( Connection* _pConnection) + : OStatementCommonBase( _pConnection), + m_pSqlda(nullptr) + {} + + virtual void disposeResultSet() override; + + DECLARE_SERVICE_INFO(); + + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + executeQuery(const OUString& sql) override; + virtual sal_Int32 SAL_CALL executeUpdate(const OUString& sqlIn) override; + virtual sal_Bool SAL_CALL + execute(const OUString& sql) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL + getConnection() override; + + // XBatchExecution - UNSUPPORTED + virtual void SAL_CALL addBatch( const OUString& sql ) override; + virtual void SAL_CALL clearBatch( ) override; + virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override; + + // XInterface + virtual css::uno::Any SAL_CALL + queryInterface(const css::uno::Type & rType) override; + + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL + getTypes() override; + // OComponentHelper + virtual void SAL_CALL disposing() override; + + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_STATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/StatementCommonBase.cxx b/connectivity/source/drivers/firebird/StatementCommonBase.cxx new file mode 100644 index 000000000..c1219d74b --- /dev/null +++ b/connectivity/source/drivers/firebird/StatementCommonBase.cxx @@ -0,0 +1,463 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Driver.hxx" +#include "StatementCommonBase.hxx" +#include "Util.hxx" + +#include <sal/log.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <propertyids.hxx> +#include <vcl/svapp.hxx> +#include <TConnection.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +using namespace ::connectivity::firebird; + +using namespace ::com::sun::star; +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::sdbcx; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::util; + +using namespace ::comphelper; +using namespace ::osl; +using namespace ::std; + +OStatementCommonBase::OStatementCommonBase(Connection* _pConnection) + : OStatementCommonBase_Base(m_aMutex), + OPropertySetHelper(OStatementCommonBase_Base::rBHelper), + m_pConnection(_pConnection), +#if SAL_TYPES_SIZEOFPOINTER == 8 + m_aStatementHandle(0) +#else + m_aStatementHandle(nullptr) +#endif +{ +} + +OStatementCommonBase::~OStatementCommonBase() +{ +} + +void OStatementCommonBase::disposeResultSet() +{ + uno::Reference< XComponent > xComp(m_xResultSet, UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + m_xResultSet.clear(); +} + +void OStatementCommonBase::freeStatementHandle() +{ + if (m_aStatementHandle) + { + isc_dsql_free_statement(m_statusVector, + &m_aStatementHandle, + DSQL_drop); + evaluateStatusVector(m_statusVector, + "isc_dsql_free_statement", + *this); + } +} + + +Any SAL_CALL OStatementCommonBase::queryInterface( const Type & rType ) +{ + Any aRet = OStatementCommonBase_Base::queryInterface(rType); + if(!aRet.hasValue()) + aRet = OPropertySetHelper::queryInterface(rType); + return aRet; +} + +Sequence< Type > SAL_CALL OStatementCommonBase::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( + ::cppu::UnoType<XMultiPropertySet>::get(), + ::cppu::UnoType<XFastPropertySet>::get(), + ::cppu::UnoType<XPropertySet>::get()); + + return concatSequences(aTypes.getTypes(),OStatementCommonBase_Base::getTypes()); +} + + +void SAL_CALL OStatementCommonBase::cancel( ) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + // cancel the current sql statement +} + +void SAL_CALL OStatementCommonBase::close() +{ + SAL_INFO("connectivity.firebird", "close"); + + { + MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + disposeResultSet(); + freeStatementHandle(); + } + + dispose(); +} + +void OStatementCommonBase::prepareAndDescribeStatement(const OUString& sql, + XSQLDA*& pOutSqlda, + XSQLDA* pInSqlda) +{ + SolarMutexGuard g; // tdf#122129 + + freeStatementHandle(); + + if (!pOutSqlda) + { + pOutSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(10))); + pOutSqlda->version = SQLDA_VERSION1; + pOutSqlda->sqln = 10; + } + + ISC_STATUS aErr = isc_dsql_allocate_statement(m_statusVector, + &m_pConnection->getDBHandle(), + &m_aStatementHandle); + + if (aErr) + { + evaluateStatusVector(m_statusVector, + "isc_dsql_allocate_statement", + *this); + } + else + { + aErr = isc_dsql_prepare(m_statusVector, + &m_pConnection->getTransaction(), + &m_aStatementHandle, + 0, + OUStringToOString(sql, RTL_TEXTENCODING_UTF8).getStr(), + FIREBIRD_SQL_DIALECT, + pInSqlda); + + if (aErr) + { + evaluateStatusVector(m_statusVector, + "isc_dsql_prepare", + *this); + } + else + { + aErr = isc_dsql_describe(m_statusVector, + &m_aStatementHandle, + 1, + pOutSqlda); + + if (aErr) + { + // TODO: free statement handle, etc.? + evaluateStatusVector(m_statusVector, + "isc_dsql_describe", + *this); + } + else + { + // Ensure we have enough space in pOutSqlda + if (pOutSqlda->sqld > pOutSqlda->sqln) + { + int n = pOutSqlda->sqld; + free(pOutSqlda); + pOutSqlda = static_cast<XSQLDA*>(calloc(1, XSQLDA_LENGTH(n))); + pOutSqlda->version = SQLDA_VERSION1; + pOutSqlda->sqln = n; + aErr = isc_dsql_describe(m_statusVector, + &m_aStatementHandle, + 1, + pOutSqlda); + } + + // Process each XSQLVAR parameter structure in the output XSQLDA + if (aErr) + { + evaluateStatusVector(m_statusVector, + "isc_dsql_describe", + *this); + } + else + { + mallocSQLVAR(pOutSqlda); + } + } + } + if(aErr) + { + freeStatementHandle(); + } + } + if(aErr) + { + free(pOutSqlda); + pOutSqlda = nullptr; + } +} + +// ---- XMultipleResults - UNSUPPORTED ---------------------------------------- +uno::Reference< XResultSet > SAL_CALL OStatementCommonBase::getResultSet() +{ + // TODO: verify we really can't support this +// return uno::Reference< XResultSet >(); + MutexGuard aGuard(m_aMutex); + checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); + + return m_xResultSet; +} + +sal_Bool SAL_CALL OStatementCommonBase::getMoreResults() +{ + // TODO: verify we really can't support this + return false; +// MutexGuard aGuard( m_aMutex ); +// checkDisposed(OStatementCommonBase_Base::rBHelper.bDisposed); +} + +sal_Int32 SAL_CALL OStatementCommonBase::getUpdateCount() +{ + // TODO: verify we really can't support this + return -1; +} + + +// ---- XWarningsSupplier - UNSUPPORTED ---------------------------------------- +Any SAL_CALL OStatementCommonBase::getWarnings() +{ + return Any(); +} + +void SAL_CALL OStatementCommonBase::clearWarnings() +{ +} + +::cppu::IPropertyArrayHelper* OStatementCommonBase::createArrayHelper( ) const +{ + // this properties are define by the service statement + // they must in alphabetic order + Sequence< Property > aProps(10); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + + +::cppu::IPropertyArrayHelper & OStatementCommonBase::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool OStatementCommonBase::convertFastPropertyValue( + Any &, + Any &, + sal_Int32, + const Any& ) +{ + // here we have to try to convert + return false; +} + +void OStatementCommonBase::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) +{ + // set the value to whatever is necessary + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + case PROPERTY_ID_USEBOOKMARKS: + default: + ; + } +} + +void OStatementCommonBase::getFastPropertyValue(Any&,sal_Int32 nHandle) const +{ + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + case PROPERTY_ID_USEBOOKMARKS: + default: + ; + } +} + +void SAL_CALL OStatementCommonBase::acquire() throw() +{ + OStatementCommonBase_Base::acquire(); +} + +void SAL_CALL OStatementCommonBase::release() throw() +{ + OStatementCommonBase_Base::release(); +} + +uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OStatementCommonBase::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +short OStatementCommonBase::getSqlInfoItem(char aInfoItem) +{ + ISC_STATUS_ARRAY aStatusVector; + ISC_STATUS aErr; + + char aInfoItems[] = {aInfoItem}; + char aResultsBuffer[8]; + + aErr = isc_dsql_sql_info(aStatusVector, + &m_aStatementHandle, + sizeof(aInfoItems), + aInfoItems, + sizeof(aResultsBuffer), + aResultsBuffer); + + if (!aErr && aResultsBuffer[0] == aInfoItem) + { + const short aBytes = static_cast<short>(isc_vax_integer(aResultsBuffer+1, 2)); + return static_cast<short>(isc_vax_integer(aResultsBuffer+3, aBytes)); + } + + evaluateStatusVector(aStatusVector, + "isc_dsq_sql_info", + *this); + return 0; +} + +bool OStatementCommonBase::isDDLStatement() +{ + return getSqlInfoItem(isc_info_sql_stmt_type) == isc_info_sql_stmt_ddl; +} + +sal_Int32 OStatementCommonBase::getStatementChangeCount() +{ + const short aStatementType = getSqlInfoItem(isc_info_sql_stmt_type); + + + ISC_STATUS_ARRAY aStatusVector; + ISC_STATUS aErr; + + // This is somewhat undocumented so I'm just guessing and hoping for the best. + char aInfoItems[] = {isc_info_sql_records}; + char aResultsBuffer[1024]; + + aErr = isc_dsql_sql_info(aStatusVector, + &m_aStatementHandle, + sizeof(aInfoItems), + aInfoItems, + sizeof(aResultsBuffer), + aResultsBuffer); + + if (aErr) + { + evaluateStatusVector(aStatusVector, + "isc_dsq_sql_info", + *this); + return 0; + } + + short aDesiredInfoType = 0; + switch (aStatementType) + { + case isc_info_sql_stmt_select: + aDesiredInfoType = isc_info_req_select_count; + break; + case isc_info_sql_stmt_insert: + aDesiredInfoType = isc_info_req_insert_count; + break; + case isc_info_sql_stmt_update: + aDesiredInfoType = isc_info_req_update_count; + break; + case isc_info_sql_stmt_delete: + aDesiredInfoType = isc_info_req_delete_count; + break; + case isc_info_sql_stmt_exec_procedure: + return 0; // cannot determine + default: + throw SQLException(); // TODO: better error message? + } + + char* pResults = aResultsBuffer; + if (static_cast<short>(*pResults++) == isc_info_sql_records) + { +// const short aTotalLength = (short) isc_vax_integer(pResults, 2); + pResults += 2; + + // Seems to be of form TOKEN (1 byte), LENGTH (2 bytes), DATA (LENGTH bytes) + while (*pResults != isc_info_rsb_end) + { + const char aToken = *pResults; + const short aLength = static_cast<short>(isc_vax_integer(pResults+1, 2)); + + if (aToken == aDesiredInfoType) + { + return isc_vax_integer(pResults + 3, aLength); + } + + pResults += (3 + aLength); + } + } + + return 0; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/StatementCommonBase.hxx b/connectivity/source/drivers/firebird/StatementCommonBase.hxx new file mode 100644 index 000000000..bce9f7374 --- /dev/null +++ b/connectivity/source/drivers/firebird/StatementCommonBase.hxx @@ -0,0 +1,136 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_STATEMENTCOMMONBASE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_STATEMENTCOMMONBASE_HXX + +#include "Connection.hxx" +#include "SubComponent.hxx" + +#include <ibase.h> + +#include <cppuhelper/compbase.hxx> + +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/util/XCancellable.hpp> + +namespace connectivity +{ + namespace firebird + { + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier, + css::util::XCancellable, + css::sdbc::XCloseable, + css::sdbc::XMultipleResults> OStatementCommonBase_Base; + + class OStatementCommonBase : public OStatementCommonBase_Base, + public ::cppu::OPropertySetHelper, + public OPropertyArrayUsageHelper<OStatementCommonBase> + + { + protected: + ::osl::Mutex m_aMutex; + + css::uno::Reference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created + // for this Statement + + ::rtl::Reference<Connection> m_pConnection; + + ISC_STATUS_ARRAY m_statusVector; + isc_stmt_handle m_aStatementHandle; + + protected: + virtual void disposeResultSet(); + /// @throws css::sdbc::SQLException + void freeStatementHandle(); + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + using OPropertySetHelper::getFastPropertyValue; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle) const override; + virtual ~OStatementCommonBase() override; + + /// @throws css::sdbc::SQLException + void prepareAndDescribeStatement(const OUString& sqlIn, + XSQLDA*& pOutSqlda, + XSQLDA* pInSqlda=nullptr); + + /// @throws css::sdbc::SQLException + short getSqlInfoItem(char aInfoItem); + /// @throws css::sdbc::SQLException + bool isDDLStatement(); + /// @throws css::sdbc::SQLException + sal_Int32 getStatementChangeCount(); + + public: + + explicit OStatementCommonBase(Connection* _pConnection); + using OStatementCommonBase_Base::operator css::uno::Reference< css::uno::XInterface >; + + // OComponentHelper + virtual void SAL_CALL disposing() override { + disposeResultSet(); + OStatementCommonBase_Base::disposing(); + } + // XInterface + virtual void SAL_CALL release() throw() override; + virtual void SAL_CALL acquire() throw() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // XWarningsSupplier - UNSUPPORTED + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XMultipleResults - UNSUPPORTED + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_STATEMENTCOMMONBASE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/SubComponent.hxx b/connectivity/source/drivers/firebird/SubComponent.hxx new file mode 100644 index 000000000..d37100670 --- /dev/null +++ b/connectivity/source/drivers/firebird/SubComponent.hxx @@ -0,0 +1,131 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_SUBCOMPONENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_SUBCOMPONENT_HXX + +#include <cppuhelper/propshlp.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> + +namespace cppu { + class IPropertyArrayHelper; +} + +namespace com +{ + namespace sun + { + namespace star + { + namespace lang + { + class XComponent; + } + } + } +} +namespace connectivity +{ + + namespace firebird + { + /// @throws css::lang::DisposedException + void checkDisposed(bool _bThrow); + + + template <class TYPE> + class OPropertyArrayUsageHelper + { + protected: + static sal_Int32 s_nRefCount; + static ::cppu::IPropertyArrayHelper* s_pProps; + static ::osl::Mutex s_aMutex; + + public: + OPropertyArrayUsageHelper(); + virtual ~OPropertyArrayUsageHelper(); + + /** call this in the getInfoHelper method of your derived class. The method returns the array helper of the + class, which is created if necessary. + */ + ::cppu::IPropertyArrayHelper* getArrayHelper(); + + protected: + /** used to implement the creation of the array helper which is shared amongst all instances of the class. + This method needs to be implemented in derived classes. + <BR> + The method gets called with s_aMutex acquired. + @return a pointer to the newly created array helper. Must not be NULL. + */ + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const = 0; + }; + + template<class TYPE> + sal_Int32 OPropertyArrayUsageHelper< TYPE >::s_nRefCount = 0; + + template<class TYPE> + ::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper< TYPE >::s_pProps = nullptr; + + template<class TYPE> + ::osl::Mutex OPropertyArrayUsageHelper< TYPE >::s_aMutex; + + + template <class TYPE> + OPropertyArrayUsageHelper<TYPE>::OPropertyArrayUsageHelper() + { + ::osl::MutexGuard aGuard(s_aMutex); + ++s_nRefCount; + } + + + template <class TYPE> + OPropertyArrayUsageHelper<TYPE>::~OPropertyArrayUsageHelper() + { + ::osl::MutexGuard aGuard(s_aMutex); + OSL_ENSURE(s_nRefCount > 0, "OPropertyArrayUsageHelper::~OPropertyArrayUsageHelper : suspicious call : have a refcount of 0 !"); + if (!--s_nRefCount) + { + delete s_pProps; + s_pProps = nullptr; + } + } + + + template <class TYPE> + ::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper<TYPE>::getArrayHelper() + { + OSL_ENSURE(s_nRefCount, "OPropertyArrayUsageHelper::getArrayHelper : suspicious call : have a refcount of 0 !"); + if (!s_pProps) + { + ::osl::MutexGuard aGuard(s_aMutex); + if (!s_pProps) + { + s_pProps = createArrayHelper(); + OSL_ENSURE(s_pProps, "OPropertyArrayUsageHelper::getArrayHelper : createArrayHelper returned nonsense !"); + } + } + return s_pProps; + } + + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_SUBCOMPONENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Table.cxx b/connectivity/source/drivers/firebird/Table.cxx new file mode 100644 index 000000000..e0eba9d7e --- /dev/null +++ b/connectivity/source/drivers/firebird/Table.cxx @@ -0,0 +1,262 @@ +/* -*- 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/. + */ + +#include "Columns.hxx" +#include "Indexes.hxx" +#include "Keys.hxx" +#include "Table.hxx" + +#include <TConnection.hxx> + +#include <sal/log.hxx> +#include <comphelper/sequence.hxx> +#include <connectivity/dbtools.hxx> + +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +using namespace ::connectivity; +using namespace ::connectivity::firebird; +using namespace ::connectivity::sdbcx; + +using namespace ::osl; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::uno; + +Table::Table(Tables* pTables, + Mutex& rMutex, + const uno::Reference< XConnection >& rConnection): + OTableHelper(pTables, + rConnection, + true), + m_rMutex(rMutex), + m_nPrivileges(0) +{ + construct(); +} + +Table::Table(Tables* pTables, + Mutex& rMutex, + const uno::Reference< XConnection >& rConnection, + const OUString& rName, + const OUString& rType, + const OUString& rDescription): + OTableHelper(pTables, + rConnection, + true, + rName, + rType, + rDescription, + "", + ""), + m_rMutex(rMutex), + m_nPrivileges(0) +{ + construct(); +} + +void Table::construct() +{ + OTableHelper::construct(); + if (isNew()) + return; + + // TODO: get privileges when in non-embedded mode. + m_nPrivileges = Privilege::DROP | + Privilege::REFERENCE | + Privilege::ALTER | + Privilege::CREATE | + Privilege::READ | + Privilege::DELETE | + Privilege::UPDATE | + Privilege::INSERT | + Privilege::SELECT; + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), + PROPERTY_ID_PRIVILEGES, + PropertyAttribute::READONLY, + &m_nPrivileges, + cppu::UnoType<decltype(m_nPrivileges)>::get()); +} +//----- OTableHelper --------------------------------------------------------- +OCollection* Table::createColumns(const ::std::vector< OUString>& rNames) +{ + return new Columns(*this, + m_rMutex, + rNames); +} + +OCollection* Table::createKeys(const ::std::vector< OUString>& rNames) +{ + return new Keys(this, + m_rMutex, + rNames); +} + +OCollection* Table::createIndexes(const ::std::vector< OUString>& rNames) +{ + return new Indexes(this, + m_rMutex, + rNames); +} + +//----- XAlterTable ----------------------------------------------------------- +void SAL_CALL Table::alterColumnByName(const OUString& rColName, + const uno::Reference< XPropertySet >& rDescriptor) +{ + MutexGuard aGuard(m_rMutex); + checkDisposed(WeakComponentImplHelperBase::rBHelper.bDisposed); + + uno::Reference< XPropertySet > xColumn(m_xColumns->getByName(rColName), UNO_QUERY); + + // sdbcx::Descriptor + const bool bNameChanged = xColumn->getPropertyValue("Name") != rDescriptor->getPropertyValue("Name"); + // sdbcx::ColumnDescriptor + const bool bTypeChanged = xColumn->getPropertyValue("Type") != rDescriptor->getPropertyValue("Type"); + const bool bTypeNameChanged = xColumn->getPropertyValue("TypeName") != rDescriptor->getPropertyValue("TypeName"); + const bool bPrecisionChanged = xColumn->getPropertyValue("Precision") != rDescriptor->getPropertyValue("Precision"); + const bool bScaleChanged = xColumn->getPropertyValue("Scale") != rDescriptor->getPropertyValue("Scale"); + const bool bIsNullableChanged = xColumn->getPropertyValue("IsNullable") != rDescriptor->getPropertyValue("IsNullable"); + const bool bIsAutoIncrementChanged = xColumn->getPropertyValue("IsAutoIncrement") != rDescriptor->getPropertyValue("IsAutoIncrement"); + + // TODO: remainder -- these are all "optional" so have to detect presence and change. + + bool bDefaultChanged = xColumn->getPropertyValue("DefaultValue") + != rDescriptor->getPropertyValue("DefaultValue"); + + if (bTypeChanged || bTypeNameChanged || bPrecisionChanged || bScaleChanged) + { + // If bPrecisionChanged this will only succeed if we have increased the + // precision, otherwise an exception is thrown -- however the base + // gui then offers to delete and recreate the column. + OUString sSql(getAlterTableColumn(rColName) + "TYPE " + + ::dbtools::createStandardTypePart(rDescriptor, getConnection())); + getConnection()->createStatement()->execute(sSql); + // TODO: could cause errors e.g. if incompatible types, deal with them here as appropriate. + // possibly we have to wrap things in Util::evaluateStatusVector. + } + + if (bIsNullableChanged) + { + sal_Int32 nNullable = 0; + rDescriptor->getPropertyValue("IsNullable") >>= nNullable; + + if (nNullable != ColumnValue::NULLABLE_UNKNOWN) + { + + OUString sSql; + // Dirty hack: can't change null directly in sql, we have to fiddle + // the system tables manually. + if (nNullable == ColumnValue::NULLABLE) + { + sSql = "UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = NULL " + "WHERE RDB$FIELD_NAME = '" + rColName + "' " + "AND RDB$RELATION_NAME = '" + getName() + "'"; + } + else if (nNullable == ColumnValue::NO_NULLS) + { + // And if we are making NOT NULL then we have to make sure we have + // no nulls left in the column. + OUString sFillNulls("UPDATE \"" + getName() + "\" SET \"" + + rColName + "\" = 0 " + "WHERE \"" + rColName + "\" IS NULL"); + getConnection()->createStatement()->execute(sFillNulls); + + sSql = "UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = 1 " + "WHERE RDB$FIELD_NAME = '" + rColName + "' " + "AND RDB$RELATION_NAME = '" + getName() + "'"; + } + getConnection()->createStatement()->execute(sSql); + } + else + { + SAL_WARN("connectivity.firebird", "Attempting to set Nullable to NULLABLE_UNKNOWN"); + } + } + + if (bIsAutoIncrementChanged) + { + ::dbtools::throwSQLException( + "Changing autoincrement property of existing column is not supported", + ::dbtools::StandardSQLState::FUNCTION_NOT_SUPPORTED, + *this); + + } + + if (bDefaultChanged) + { + OUString sNewDefault; + rDescriptor->getPropertyValue("DefaultValue") >>= sNewDefault; + + OUString sSql; + if (sNewDefault.isEmpty()) + sSql = getAlterTableColumn(rColName) + "DROP DEFAULT"; + else + sSql = getAlterTableColumn(rColName) + "SET DEFAULT " + sNewDefault; + + getConnection()->createStatement()->execute(sSql); + } + // TODO: quote identifiers as needed. + if (bNameChanged) + { + OUString sNewColName; + rDescriptor->getPropertyValue("Name") >>= sNewColName; + OUString sSql(getAlterTableColumn(rColName) + + " TO \"" + sNewColName + "\""); + + getConnection()->createStatement()->execute(sSql); + } + + + m_xColumns->refresh(); +} + +// ----- XRename -------------------------------------------------------------- +void SAL_CALL Table::rename(const OUString&) +{ + throw RuntimeException("Table renaming not supported by Firebird."); +} + +// ----- XInterface ----------------------------------------------------------- +Any SAL_CALL Table::queryInterface(const Type& rType) +{ + if (rType.getTypeName() == "com.sun.star.sdbcx.XRename") + return Any(); + + return OTableHelper::queryInterface(rType); +} + +// ----- XTypeProvider -------------------------------------------------------- +uno::Sequence< Type > SAL_CALL Table::getTypes() +{ + uno::Sequence< Type > aTypes = OTableHelper::getTypes(); + + for (int i = 0; i < aTypes.getLength(); i++) + { + if (aTypes[i].getTypeName() == "com.sun.star.sdbcx.XRename") + { + ::comphelper::removeElementAt(aTypes, i); + break; + } + } + + return OTableHelper::getTypes(); +} + +OUString Table::getAlterTableColumn(const OUString& rColumn) +{ + return ("ALTER TABLE \"" + getName() + "\" ALTER COLUMN \"" + rColumn + "\" "); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Table.hxx b/connectivity/source/drivers/firebird/Table.hxx new file mode 100644 index 000000000..586152ecc --- /dev/null +++ b/connectivity/source/drivers/firebird/Table.hxx @@ -0,0 +1,87 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_TABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_TABLE_HXX + +#include "Tables.hxx" + +#include <connectivity/TTableHelper.hxx> + +namespace connectivity +{ + namespace firebird + { + + /** + * Implements sdbcx.Table. We don't support table renaming (XRename) + * hence the appropriate methods are overridden. + */ + class Table: public OTableHelper + { + private: + ::osl::Mutex& m_rMutex; + sal_Int32 m_nPrivileges; + + /** + * Get the ALTER TABLE [TABLE] ALTER [COLUMN] String. + * Includes a trailing space. + */ + OUString getAlterTableColumn(const OUString& rColumn); + + protected: + void construct() override; + + public: + Table(Tables* pTables, + ::osl::Mutex& rMutex, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + Table(Tables* pTables, + ::osl::Mutex& rMutex, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const OUString& rName, + const OUString& rType, + const OUString& rDescription); + + // OTableHelper + virtual ::connectivity::sdbcx::OCollection* createColumns( + const ::std::vector< OUString>& rNames) override; + virtual ::connectivity::sdbcx::OCollection* createKeys( + const ::std::vector< OUString>& rNames) override; + virtual ::connectivity::sdbcx::OCollection* createIndexes( + const ::std::vector< OUString>& rNames) override; + + // XAlterTable + /** + * See css::sdbcx::ColumnDescriptor for details of + * rDescriptor. + */ + virtual void SAL_CALL alterColumnByName( + const OUString& rColName, + const css::uno::Reference< css::beans::XPropertySet >& rDescriptor) override; + + // XRename -- UNSUPPORTED + virtual void SAL_CALL rename(const OUString& sName) override; + + //XInterface + virtual css::uno::Any + SAL_CALL queryInterface(const css::uno::Type & rType) override; + + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > + SAL_CALL getTypes() override; + + }; + + } // namespace firebird +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_TABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Tables.cxx b/connectivity/source/drivers/firebird/Tables.cxx new file mode 100644 index 000000000..5acb391ca --- /dev/null +++ b/connectivity/source/drivers/firebird/Tables.cxx @@ -0,0 +1,211 @@ +/* -*- 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/. + */ + +#include "Table.hxx" +#include "Tables.hxx" +#include "Catalog.hxx" +#include "Util.hxx" + +#include <TConnection.hxx> + +#include <connectivity/dbtools.hxx> + +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <comphelper/types.hxx> + +using namespace ::connectivity; +using namespace ::connectivity::firebird; +using namespace ::connectivity::sdbcx; +using namespace ::cppu; +using namespace ::osl; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::uno; + + +//----- OCollection ----------------------------------------------------------- +void Tables::impl_refresh() +{ + static_cast<Catalog&>(m_rParent).refreshTables(); +} + +ObjectType Tables::createObject(const OUString& rName) +{ + // Only retrieving a single table, so table type is irrelevant (param 4) + uno::Reference< XResultSet > xTables = m_xMetaData->getTables(Any(), + OUString(), + rName, + uno::Sequence< OUString >()); + + if (!xTables.is()) + throw RuntimeException("Could not acquire table."); + + uno::Reference< XRow > xRow(xTables,UNO_QUERY_THROW); + + if (!xTables->next()) + throw RuntimeException(); + + ObjectType xRet(new Table(this, + m_rMutex, + m_xMetaData->getConnection(), + xRow->getString(3), // Name + xRow->getString(4), // Type + xRow->getString(5))); // Description / Remarks / Comments + + if (xTables->next()) + throw RuntimeException("Found more tables than expected."); + + return xRet; +} + +OUString Tables::createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection) +{ + 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(" "); + + aSql.append(dbtools::createStandardTypePart(xColProp, _xConnection)); + // Add character set for (VAR)BINARY (fix) types: + // (VAR) BINARY is distinguished from other CHAR types by its character set. + // Octets is a special character set for binary data. + if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex( + PROPERTY_ID_TYPE)) ) + { + sal_Int32 aType = 0; + xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_TYPE)) + >>= aType; + if(aType == DataType::BINARY || aType == DataType::VARBINARY) + { + aSql.append(" "); + aSql.append("CHARACTER SET OCTETS"); + } + } + + if ( bIsAutoIncrement && !sAutoIncrementValue.isEmpty()) + { + aSql.append(" "); + aSql.append(sAutoIncrementValue); + } + // AutoIncrement "IDENTITY" is implicitly "NOT NULL" + else if(::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISNULLABLE))) == ColumnValue::NO_NULLS) + aSql.append(" NOT NULL"); + + return aSql.makeStringAndClear(); +} + +uno::Reference< XPropertySet > Tables::createDescriptor() +{ + // There is some internal magic so that the same class can be used as either + // a descriptor or as a normal table. See VTable.cxx for the details. In our + // case we just need to ensure we use the correct constructor. + return new Table(this, m_rMutex, m_xMetaData->getConnection()); +} + +//----- XAppend --------------------------------------------------------------- +ObjectType Tables::appendObject(const OUString& rName, + const uno::Reference< XPropertySet >& rDescriptor) +{ + /* OUString sSql(::dbtools::createSqlCreateTableStatement(rDescriptor, + m_xMetaData->getConnection())); */ + OUStringBuffer aSqlBuffer("CREATE TABLE "); + OUString sCatalog, sSchema, sComposedName, sTable; + const Reference< XConnection>& xConnection = m_xMetaData->getConnection(); + + ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap(); + + rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME)) >>= sCatalog; + rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME)) >>= sSchema; + rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME)) >>= sTable; + + sComposedName = ::dbtools::composeTableName(m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions ); + if ( sComposedName.isEmpty() ) + ::dbtools::throwFunctionSequenceException(xConnection); + + aSqlBuffer.append(sComposedName); + aSqlBuffer.append(" ("); + + // columns + Reference<XColumnsSupplier> xColumnSup(rDescriptor,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() ) + { + aSqlBuffer.append(createStandardColumnPart(xColProp,xConnection)); + aSqlBuffer.append(","); + } + } + OUString sSql = aSqlBuffer.makeStringAndClear(); + + const OUString sKeyStmt = ::dbtools::createStandardKeyStatement(rDescriptor,xConnection); + if ( !sKeyStmt.isEmpty() ) + sSql += sKeyStmt; + else + { + if ( sSql.endsWith(",") ) + sSql = sSql.replaceAt(sSql.getLength()-1, 1, ")"); + else + sSql += ")"; + } + + m_xMetaData->getConnection()->createStatement()->execute(sSql); + + return createObject(rName); +} + +//----- XDrop ----------------------------------------------------------------- +void Tables::dropObject(sal_Int32 nPosition, const OUString& sName) +{ + uno::Reference< XPropertySet > xTable(getObject(nPosition)); + + if (ODescriptor::isNew(xTable)) + return; + + OUStringBuffer sSql("DROP "); + + OUString sType; + xTable->getPropertyValue("Type") >>= sType; + sSql.append(sType); + + const OUString sQuoteString = m_xMetaData->getIdentifierQuoteString(); + sSql.append(::dbtools::quoteName(sQuoteString,sName)); + + m_xMetaData->getConnection()->createStatement()->execute(sSql.makeStringAndClear()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Tables.hxx b/connectivity/source/drivers/firebird/Tables.hxx new file mode 100644 index 000000000..635774727 --- /dev/null +++ b/connectivity/source/drivers/firebird/Tables.hxx @@ -0,0 +1,65 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_TABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_TABLES_HXX + +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> + +#include <connectivity/sdbcx/VCollection.hxx> + +namespace connectivity +{ + namespace firebird + { + + /** + * This implements com.sun.star.sdbcx.Container, which seems to be + * also known by the name of Tables and Collection. + */ + class Tables: public ::connectivity::sdbcx::OCollection + { + protected: + css::uno::Reference< css::sdbc::XDatabaseMetaData > + m_xMetaData; + + static OUString createStandardColumnPart(const css::uno::Reference< css::beans::XPropertySet >& xColProp,const css::uno::Reference< com::sun::star::sdbc::XConnection>& _xConnection); + + // OCollection + virtual void impl_refresh() override; + virtual ::connectivity::sdbcx::ObjectType createObject( + const OUString& rName) override; + virtual css::uno::Reference< css::beans::XPropertySet > + createDescriptor() override; + virtual ::connectivity::sdbcx::ObjectType appendObject( + const OUString& rName, + const css::uno::Reference< css::beans::XPropertySet >& rDescriptor) override; + + public: + Tables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& rMetaData, + ::cppu::OWeakObject& rParent, + ::osl::Mutex& rMutex, + ::std::vector< OUString> const & rNames) : sdbcx::OCollection(rParent, true, rMutex, rNames), m_xMetaData(rMetaData) {} + + // TODO: we should also implement XDataDescriptorFactory, XRefreshable, + // XAppend, etc., but all are optional. + + // XDrop + virtual void dropObject(sal_Int32 nPosition, const OUString& rName) override; + + }; + + } // namespace firebird +} // namespace connectivity + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_TABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/User.cxx b/connectivity/source/drivers/firebird/User.cxx new file mode 100644 index 000000000..3a9682fb8 --- /dev/null +++ b/connectivity/source/drivers/firebird/User.cxx @@ -0,0 +1,51 @@ +/* -*- 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/. + */ + +#include "User.hxx" + +using namespace ::connectivity; +using namespace ::connectivity::firebird; +using namespace ::connectivity::sdbcx; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdbc; + +User::User(const css::uno::Reference< css::sdbc::XConnection >& rConnection): + OUser(true) // Case Sensitive + , m_xConnection(rConnection) +{} + +User::User(const css::uno::Reference< css::sdbc::XConnection >& rConnection, const OUString& rName): + OUser(rName, + true) // Case Sensitive + , m_xConnection(rConnection) +{} + +void User::changePassword(const OUString&, const OUString& newPassword) +{ + m_xConnection->createStatement()->execute("ALTER USER " + m_Name + " PASSWORD '" + newPassword + "'"); +} + +sal_Int32 User::getPrivileges(const OUString& , sal_Int32 ) +{ + // TODO: implement. + return 0; +} + +sal_Int32 User::getGrantablePrivileges(const OUString& , sal_Int32 ) +{ + // TODO: implement. + return 0; +} + +//----- IRefreshableGroups ---------------------------------------------------- +void User::refreshGroups() +{ + // TODO: implement. +} diff --git a/connectivity/source/drivers/firebird/User.hxx b/connectivity/source/drivers/firebird/User.hxx new file mode 100644 index 000000000..5668c3223 --- /dev/null +++ b/connectivity/source/drivers/firebird/User.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_USER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_USER_HXX + +#include <sdbcx/VUser.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> + +namespace connectivity +{ + namespace firebird + { + + /** + * This implements com.sun.star.sdbcx.Container. + */ + class User: public ::connectivity::sdbcx::OUser + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + + public: + /** + * Create a "new" descriptor, which isn't yet in the database. + */ + User(const css::uno::Reference< css::sdbc::XConnection >& rConnection); + /** + * For a user that already exists in the db. + */ + User(const css::uno::Reference< css::sdbc::XConnection >& rConnection, const OUString& rName); + + // XAuthorizable + virtual void SAL_CALL changePassword(const OUString&, const OUString& newPassword) override; + virtual sal_Int32 SAL_CALL getPrivileges(const OUString&, sal_Int32) override; + virtual sal_Int32 SAL_CALL getGrantablePrivileges(const OUString&, sal_Int32) override; + + // IRefreshableGroups:: + virtual void refreshGroups() override; + }; + + } // namespace firebird +} // namespace connectivity + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_USER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Users.cxx b/connectivity/source/drivers/firebird/Users.cxx new file mode 100644 index 000000000..fc8914250 --- /dev/null +++ b/connectivity/source/drivers/firebird/Users.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "User.hxx" +#include "Users.hxx" + +using namespace ::connectivity; +using namespace ::connectivity::firebird; +using namespace ::connectivity::sdbcx; +using namespace ::cppu; +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + + +Users::Users(const uno::Reference< XDatabaseMetaData >& rMetaData, + OWeakObject& rParent, + Mutex& rMutex, + ::std::vector< OUString> const & rNames) : + OCollection(rParent, + true, + rMutex, + rNames), + m_xMetaData(rMetaData) +{ +} + +//----- OCollection ----------------------------------------------------------- +void Users::impl_refresh() +{ + // TODO: IMPLEMENT ME +} + +ObjectType Users::createObject(const OUString& rName) +{ + return new User(m_xMetaData->getConnection(), rName); +} + +uno::Reference< XPropertySet > Users::createDescriptor() +{ + // There is some internal magic so that the same class can be used as either + // a descriptor or as a normal user. See VUser.cxx for the details. In our + // case we just need to ensure we use the correct constructor. + return new User(m_xMetaData->getConnection()); +} + +//----- XAppend --------------------------------------------------------------- +ObjectType Users::appendObject(const OUString& rName, + const uno::Reference< XPropertySet >&) +{ + // TODO: set sSql as appropriate + m_xMetaData->getConnection()->createStatement()->execute(OUString()); + + return createObject(rName); +} + +//----- XDrop ----------------------------------------------------------------- +void Users::dropObject(sal_Int32 nPosition, const OUString&) +{ + uno::Reference< XPropertySet > xUser(getObject(nPosition)); + + if (!ODescriptor::isNew(xUser)) + { + // TODO: drop me + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Users.hxx b/connectivity/source/drivers/firebird/Users.hxx new file mode 100644 index 000000000..39e019e4d --- /dev/null +++ b/connectivity/source/drivers/firebird/Users.hxx @@ -0,0 +1,60 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_USERS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_USERS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> + +namespace connectivity +{ + namespace firebird + { + + /** + * This implements com.sun.star.sdbcx.Container. + */ + class Users: public ::connectivity::sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XDatabaseMetaData > + m_xMetaData; + protected: + + // OCollection + virtual void impl_refresh() override; + virtual ::connectivity::sdbcx::ObjectType createObject( + const OUString& rName) override; + virtual css::uno::Reference< css::beans::XPropertySet > + createDescriptor() override; + virtual ::connectivity::sdbcx::ObjectType appendObject( + const OUString& rName, + const css::uno::Reference< css::beans::XPropertySet >& rDescriptor) override; + + public: + Users(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& rMetaData, + ::cppu::OWeakObject& rParent, + ::osl::Mutex& rMutex, + ::std::vector< OUString> const & rNames); + + // TODO: we should also implement XDataDescriptorFactory, XRefreshable, + // XAppend, etc., but all are optional. + + // XDrop + virtual void dropObject(sal_Int32 nPosition, const OUString& rName) override; + + }; + + } // namespace firebird +} // namespace connectivity + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_USERS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Util.cxx b/connectivity/source/drivers/firebird/Util.cxx new file mode 100644 index 000000000..64e329723 --- /dev/null +++ b/connectivity/source/drivers/firebird/Util.cxx @@ -0,0 +1,436 @@ +/* -*- 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/. + */ + +#include "Util.hxx" +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +using namespace ::connectivity; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +using namespace firebird; + +OUString firebird::sanitizeIdentifier(const OUString& rIdentifier) +{ + OUString sRet = rIdentifier.trim(); + assert(sRet.getLength() <= 31); // Firebird identifiers cannot be longer than this. + + return sRet; +} + +OUString firebird::StatusVectorToString(const ISC_STATUS_ARRAY& rStatusVector, + const OUString& rCause) +{ + OUStringBuffer buf; + const ISC_STATUS* pStatus = reinterpret_cast<const ISC_STATUS*>(&rStatusVector); + + buf.append("firebird_sdbc error:"); + try + { + char msg[512]; // Size is based on suggestion in docs. + while(fb_interpret(msg, sizeof(msg), &pStatus)) + { + // TODO: verify encoding + buf.append("\n*"); + buf.append(OUString(msg, strlen(msg), RTL_TEXTENCODING_UTF8)); + } + } + catch (...) + { + SAL_WARN("connectivity.firebird", "ignore fb_interpret exception"); + } + buf.append("\ncaused by\n'").append(rCause).append("'\n"); + + OUString error = buf.makeStringAndClear(); + SAL_WARN("connectivity.firebird", error); + return error; +} + +void firebird::evaluateStatusVector(const ISC_STATUS_ARRAY& rStatusVector, + const OUString& rCause, + const uno::Reference< XInterface >& _rxContext) +{ + if (IndicatesError(rStatusVector)) + { + OUString error = StatusVectorToString(rStatusVector, rCause); + throw SQLException(error, _rxContext, OUString(), 1, Any()); + } +} + +static sal_Int32 lcl_getNumberType( short aType, NumberSubType aSubType ) +{ + switch(aSubType) + { + case NumberSubType::Numeric: + return DataType::NUMERIC; + case NumberSubType::Decimal: + return DataType::DECIMAL; + default: + switch(aType) + { + case SQL_SHORT: + return DataType::SMALLINT; + case SQL_LONG: + return DataType::INTEGER; + case SQL_DOUBLE: + return DataType::DOUBLE; + case SQL_INT64: + return DataType::BIGINT; + default: + assert(false); // not a number + return 0; + } + } +} +static sal_Int32 lcl_getCharColumnType( short aType, const OUString& sCharset ) +{ + switch(aType) + { + case SQL_TEXT: + if( sCharset == "OCTETS") + return DataType::BINARY; + else + return DataType::CHAR; + case SQL_VARYING: + if( sCharset == "OCTETS") + return DataType::VARBINARY; + else + return DataType::VARCHAR; + default: + assert(false); + return 0; + } +} + +sal_Int32 firebird::ColumnTypeInfo::getSdbcType() const +{ + short aType = m_aType & ~1; // Remove last bit -- it is used to denote whether column + // can store Null, not needed for type determination + short aSubType = m_aSubType; + if( m_nScale > 0 ) + { + // numeric / decimal + if(aType == SQL_SHORT || aType == SQL_LONG || aType == SQL_DOUBLE + || aType == SQL_INT64) + { + // if scale is set without subtype then imply numeric + if( static_cast<NumberSubType>(aSubType) == NumberSubType::Other ) + aSubType = static_cast<short>(NumberSubType::Numeric); + } + } + + switch (aType) + { + case SQL_TEXT: + case SQL_VARYING: + return lcl_getCharColumnType(aType, m_sCharsetName); + case SQL_SHORT: + case SQL_LONG: + case SQL_DOUBLE: + case SQL_INT64: + return lcl_getNumberType(aType, static_cast<NumberSubType>(aSubType) ); + case SQL_FLOAT: + return DataType::FLOAT; + case SQL_D_FLOAT: + return DataType::DOUBLE; + case SQL_TIMESTAMP: + return DataType::TIMESTAMP; + case SQL_BLOB: + switch (static_cast<BlobSubtype>(aSubType)) + { + case BlobSubtype::Blob: + return DataType::BLOB; + case BlobSubtype::Clob: + return DataType::CLOB; + case BlobSubtype::Image: + return DataType::LONGVARBINARY; + default: + SAL_WARN("connectivity.firebird", "Unknown subtype for Blob type: " << aSubType); + assert(!"Unknown subtype for Blob type"); // Should never happen + return 0; + } + case SQL_ARRAY: + return DataType::ARRAY; + case SQL_TYPE_TIME: + return DataType::TIME; + case SQL_TYPE_DATE: + return DataType::DATE; + case SQL_NULL: + return DataType::SQLNULL; + case SQL_QUAD: // Is a "Blob ID" according to the docs + return 0; // TODO: verify + case SQL_BOOLEAN: + return DataType::BOOLEAN; + default: + assert(false); // Should never happen + return 0; + } +} + +OUString firebird::ColumnTypeInfo::getColumnTypeName() const +{ + sal_Int32 nDataType = this->getSdbcType(); + switch (nDataType) + { + case DataType::BIT: + return "BIT"; + case DataType::TINYINT: + return "TINYINT"; + case DataType::SMALLINT: + return "SMALLINT"; + case DataType::INTEGER: + return "INTEGER"; + case DataType::BIGINT: + return "BIGINT"; + case DataType::FLOAT: + return "FLOAT"; + case DataType::REAL: + return "REAL"; + case DataType::DOUBLE: + return "DOUBLE"; + case DataType::NUMERIC: + return "NUMERIC"; + case DataType::DECIMAL: + return "DECIMAL"; + case DataType::CHAR: + return "CHAR"; + case DataType::VARCHAR: + return "VARCHAR"; + case DataType::LONGVARCHAR: + return "LONGVARCHAR"; + case DataType::DATE: + return "DATE"; + case DataType::TIME: + return "TIME"; + case DataType::TIMESTAMP: + return "TIMESTAMP"; + case DataType::BINARY: + // in Firebird, that is the same datatype "CHAR" as DataType::CHAR, + // only with CHARACTER SET OCTETS; we use the synonym CHARACTER + // to fool LO into seeing it as different types. + return "CHARACTER"; + case DataType::VARBINARY: + // see above comment about DataType::BINARY. + return "CHARACTER VARYING"; + case DataType::LONGVARBINARY: + return "BLOB SUB_TYPE " + OUString::number(static_cast<short>(BlobSubtype::Image)); + case DataType::ARRAY: + return "ARRAY"; + case DataType::BLOB: + return "BLOB SUB_TYPE BINARY"; + case DataType::CLOB: + return "BLOB SUB_TYPE TEXT"; + case DataType::BOOLEAN: + return "BOOLEAN"; + case DataType::SQLNULL: + return "NULL"; + default: + assert(false); // Should never happen + return OUString(); + } +} + +short firebird::getFBTypeFromBlrType(short blrType) +{ + switch (blrType) + { + case blr_text: + return SQL_TEXT; + case blr_text2: + assert(false); + return 0; // No idea if this should be supported + case blr_varying: + return SQL_VARYING; + case blr_varying2: + assert(false); + return 0; // No idea if this should be supported + case blr_short: + return SQL_SHORT; + case blr_long: + return SQL_LONG; + case blr_float: + return SQL_FLOAT; + case blr_double: + return SQL_DOUBLE; + case blr_d_float: + return SQL_D_FLOAT; + case blr_timestamp: + return SQL_TIMESTAMP; + case blr_blob: + return SQL_BLOB; +// case blr_SQL_ARRAY: +// return OUString("SQL_ARRAY"); + case blr_sql_time: + return SQL_TYPE_TIME; + case blr_sql_date: + return SQL_TYPE_DATE; + case blr_int64: + return SQL_INT64; +// case SQL_NULL: +// return OUString("SQL_NULL"); + case blr_quad: + return SQL_QUAD; + case blr_bool: + return SQL_BOOLEAN; + default: + // If this happens we have hit one of the extra types in ibase.h + // look up blr_* for a list, e.g. blr_domain_name, blr_not_nullable etc. + assert(false); + return 0; + } +} + +void firebird::mallocSQLVAR(XSQLDA* pSqlda) +{ + // TODO: confirm the sizings below. + XSQLVAR* pVar = pSqlda->sqlvar; + for (int i=0; i < pSqlda->sqld; i++, pVar++) + { + int dtype = (pVar->sqltype & ~1); /* drop flag bit for now */ + switch(dtype) { + case SQL_TEXT: + pVar->sqldata = static_cast<char *>(malloc(sizeof(char)*pVar->sqllen)); + break; + case SQL_VARYING: + pVar->sqldata = static_cast<char *>(malloc(sizeof(char)*pVar->sqllen + 2)); + break; + case SQL_SHORT: + pVar->sqldata = static_cast<char*>(malloc(sizeof(sal_Int16))); + break; + case SQL_LONG: + pVar->sqldata = static_cast<char*>(malloc(sizeof(sal_Int32))); + break; + case SQL_FLOAT: + pVar->sqldata = static_cast<char *>(malloc(sizeof(float))); + break; + case SQL_DOUBLE: + pVar->sqldata = static_cast<char *>(malloc(sizeof(double))); + break; + case SQL_D_FLOAT: + pVar->sqldata = static_cast<char *>(malloc(sizeof(double))); + break; + case SQL_TIMESTAMP: + pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_TIMESTAMP))); + break; + // an ARRAY is in fact a BLOB of a specialized type + // See https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-datatypes-bnrytypes.html#fblangref25-datatypes-array + case SQL_ARRAY: + case SQL_BLOB: + pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_QUAD))); + break; + case SQL_TYPE_TIME: + pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_TIME))); + break; + case SQL_TYPE_DATE: + pVar->sqldata = static_cast<char*>(malloc(sizeof(ISC_DATE))); + break; + case SQL_INT64: + pVar->sqldata = static_cast<char *>(malloc(sizeof(sal_Int64))); + break; + case SQL_BOOLEAN: + pVar->sqldata = static_cast<char *>(malloc(sizeof(sal_Bool))); + break; + case SQL_NULL: + assert(false); // TODO: implement + break; + case SQL_QUAD: + assert(false); // TODO: implement + break; + default: + SAL_WARN("connectivity.firebird", "Unknown type: " << dtype); + assert(false); + break; + } + /* allocate variable to hold NULL status */ + pVar->sqlind = static_cast<short *>(malloc(sizeof(short))); + } +} + +void firebird::freeSQLVAR(XSQLDA* pSqlda) +{ + XSQLVAR* pVar = pSqlda->sqlvar; + for (int i=0; i < pSqlda->sqld; i++, pVar++) + { + int dtype = (pVar->sqltype & ~1); /* drop flag bit for now */ + switch(dtype) { + case SQL_TEXT: + case SQL_VARYING: + case SQL_SHORT: + case SQL_LONG: + case SQL_FLOAT: + case SQL_DOUBLE: + case SQL_D_FLOAT: + case SQL_TIMESTAMP: + // an ARRAY is in fact a BLOB of a specialized type + // See https://firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-datatypes-bnrytypes.html#fblangref25-datatypes-array + case SQL_ARRAY: + case SQL_BLOB: + case SQL_INT64: + case SQL_TYPE_TIME: + case SQL_TYPE_DATE: + case SQL_BOOLEAN: + if(pVar->sqldata) + { + free(pVar->sqldata); + pVar->sqldata = nullptr; + } + break; + case SQL_NULL: + assert(false); // TODO: implement + break; + case SQL_QUAD: + assert(false); // TODO: implement + break; + default: + SAL_WARN("connectivity.firebird", "Unknown type: " << dtype); +// assert(false); + break; + } + + if(pVar->sqlind) + { + free(pVar->sqlind); + pVar->sqlind = nullptr; + } + } +} + + +OUString firebird::escapeWith( const OUString& sText, const char aKey, const char aEscapeChar) +{ + OUString sRet(sText); + sal_Int32 aIndex = 0; + for (;;) + { + aIndex = sRet.indexOf(aKey, aIndex); + if ( aIndex <= 0 || aIndex >= sRet.getLength()) + break; + sRet = sRet.replaceAt(aIndex, 1, OUStringChar(aEscapeChar) + OUStringChar(aKey) ); + aIndex += 2; + } + + return sRet; +} + +sal_Int64 firebird::pow10Integer(int nDecimalCount) +{ + sal_Int64 nRet = 1; + for(int i=0; i< nDecimalCount; i++) + { + nRet *= 10; + } + return nRet; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Util.hxx b/connectivity/source/drivers/firebird/Util.hxx new file mode 100644 index 000000000..107840876 --- /dev/null +++ b/connectivity/source/drivers/firebird/Util.hxx @@ -0,0 +1,130 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_UTIL_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_UTIL_HXX + +#include <ibase.h> + +#include <rtl/ustring.hxx> + +#include <com/sun/star/uno/XInterface.hpp> + +namespace connectivity +{ + namespace firebird + { + // Type Blob has 2 subtypes values + // 0 for BLOB, 1 for CLOB + // see http://www.firebirdfaq.org/faq48/ + // User-defined subtypes are negative. + // Use a number for image which is very unlikely to be defined by a + // user. + enum class BlobSubtype { + Blob = 0, + Clob = 1, + Image = -9546 + }; + + /** + * Numeric and decimal types can be identified by their subtype in + * Firebird API. 1 for NUMERIC, 2 for DECIMAL. + */ + enum class NumberSubType { + Other = 0, + Numeric = 1, + Decimal = 2 + }; + + class ColumnTypeInfo { +private: + short m_aType; + short m_aSubType; + short m_nScale; + OUString m_sCharsetName; +public: + /** + * @param tType SQL type of column defined by Firebird (e.g. + * SQL_DOUBLE) + * @param aSubType SQL sub type as in firebird API. See + * NumberSubType. + * @param scale: Scale of the number. It is ignored in case it's not + * a number. Scale obtained from the Firebird API is negative, so + * that should be negated before passing to this constructor. + * + */ + explicit ColumnTypeInfo( short aType, short aSubType = 0, + short nScale = 0, const OUString& sCharset = OUString() ) + : m_aType(aType) + , m_aSubType(aSubType) + , m_nScale(nScale) + , m_sCharsetName(sCharset) {} + explicit ColumnTypeInfo( short aType, const OUString& sCharset ) + : m_aType(aType) + , m_aSubType(0) + , m_nScale(0) + , m_sCharsetName(sCharset) {} + short getType() const { return m_aType; } + short getSubType() const { return m_aSubType; } + short getScale() const { return m_nScale; } + OUString const & getCharacterSet() const { return m_sCharsetName; } + + sal_Int32 getSdbcType() const; + OUString getColumnTypeName() const; + + }; + + /** + * Make sure an identifier is safe to use within the database. Currently + * firebird seems to return identifiers with 93 character (instead of + * 31), whereby the name is simply padded with trailing whitespace. + * This removes all trailing whitespace (i.e. if necessary so that + * the length is below 31 characters). Firebird automatically compensates + * for such shorter strings, however any trailing padding makes the gui + * editing of such names harder, hence we remove all trailing whitespace. + */ + OUString sanitizeIdentifier(const OUString& rIdentifier); + + inline bool IndicatesError(const ISC_STATUS_ARRAY& rStatusVector) + { + return rStatusVector[0]==1 && rStatusVector[1]; // indicates error; + } + + OUString StatusVectorToString(const ISC_STATUS_ARRAY& rStatusVector, + const OUString& rCause); + + /** + * Evaluate a firebird status vector and throw exceptions as necessary. + * The content of the status vector is included in the thrown exception. + * + * @throws css::sdbc::SQLException + */ + void evaluateStatusVector(const ISC_STATUS_ARRAY& rStatusVector, + const OUString& aCause, + const css::uno::Reference< css::uno::XInterface >& _rxContext); + + /** + * Internally (i.e. in RDB$FIELD_TYPE) firebird stores the data type + * for a column as defined in blr_*, however in the firebird + * api the SQL_* types are used, hence we need to be able to convert + * between the two when retrieving column metadata. + */ + short getFBTypeFromBlrType(short blrType); + + void mallocSQLVAR(XSQLDA* pSqlda); + + void freeSQLVAR(XSQLDA* pSqlda); + + OUString escapeWith( const OUString& sText, const char aKey, const char aEscapeChar); + sal_Int64 pow10Integer( int nDecimalCount ); + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_UTIL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/firebird_sdbc.component b/connectivity/source/drivers/firebird/firebird_sdbc.component new file mode 100644 index 000000000..b56d4e0bc --- /dev/null +++ b/connectivity/source/drivers/firebird/firebird_sdbc.component @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="firebird_sdbc" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.firebird.Driver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> + diff --git a/connectivity/source/drivers/flat/ECatalog.cxx b/connectivity/source/drivers/flat/ECatalog.cxx new file mode 100644 index 000000000..b656b29c2 --- /dev/null +++ b/connectivity/source/drivers/flat/ECatalog.cxx @@ -0,0 +1,60 @@ +/* -*- 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 <flat/ECatalog.hxx> + +#include <flat/EConnection.hxx> +#include <flat/ETables.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> + +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 connectivity::flat; + +OFlatCatalog::OFlatCatalog(OFlatConnection* _pCon) : file::OFileCatalog(_pCon) +{ +} + +void OFlatCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + Sequence< OUString > aTypes; + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), + "%", "%", aTypes); + + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while(xResult->next()) + aVector.push_back(xRow->getString(3)); + } + if(m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset( new OFlatTables(m_xMetaData,*this,m_aMutex,aVector) ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EColumns.cxx b/connectivity/source/drivers/flat/EColumns.cxx new file mode 100644 index 000000000..a9e210321 --- /dev/null +++ b/connectivity/source/drivers/flat/EColumns.cxx @@ -0,0 +1,44 @@ +/* -*- 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 <flat/EColumns.hxx> +#include <flat/ETable.hxx> + +using namespace connectivity::flat; +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; + + +sdbcx::ObjectType OFlatColumns::createObject(const OUString& _rName) +{ + OFlatTable* pTable = static_cast<OFlatTable*>(m_pTable); + const ::rtl::Reference<OSQLColumns>& aCols = pTable->getTableColumns(); + OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive())); + sdbcx::ObjectType xRet; + if(aIter != aCols->end()) + xRet = sdbcx::ObjectType(*aIter,UNO_QUERY); + return xRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EConnection.cxx b/connectivity/source/drivers/flat/EConnection.cxx new file mode 100644 index 000000000..5127d903c --- /dev/null +++ b/connectivity/source/drivers/flat/EConnection.cxx @@ -0,0 +1,182 @@ +/* -*- 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 <flat/EConnection.hxx> +#include <flat/EDatabaseMetaData.hxx> +#include <flat/ECatalog.hxx> +#include <flat/EDriver.hxx> +#include <flat/EPreparedStatement.hxx> +#include <flat/EStatement.hxx> +#include <connectivity/dbexception.hxx> +#include <sal/log.hxx> + +using namespace connectivity::flat; +using namespace connectivity::file; + +typedef connectivity::file::OConnection OConnection_B; + + +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::lang; + + +OFlatConnection::OFlatConnection(ODriver* _pDriver) : OConnection(_pDriver) + ,m_nMaxRowsToScan(50) + ,m_bHeaderLine(true) + ,m_cFieldDelimiter(';') + ,m_cStringDelimiter('"') + ,m_cDecimalDelimiter(',') + ,m_cThousandDelimiter('.') +{ +} + +OFlatConnection::~OFlatConnection() +{ +} + +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OFlatConnection, "com.sun.star.sdbc.drivers.flat.Connection", "com.sun.star.sdbc.Connection") + + +void OFlatConnection::construct(const OUString& url,const Sequence< PropertyValue >& info) +{ + osl_atomic_increment( &m_refCount ); + + const PropertyValue *pBegin = info.getConstArray(); + const PropertyValue *pEnd = pBegin + info.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(pBegin->Name == "HeaderLine") + { + if( ! (pBegin->Value >>= m_bHeaderLine) ) + SAL_WARN("connectivity.flat", "construct: unable to get property HeaderLine"); + } + else if(pBegin->Name == "FieldDelimiter") + { + OUString aVal; + if( ! (pBegin->Value >>= aVal) ) + SAL_WARN("connectivity.flat", "construct: unable to get property FieldDelimiter"); + + m_cFieldDelimiter = aVal.toChar(); + } + else if(pBegin->Name == "StringDelimiter") + { + OUString aVal; + if( ! (pBegin->Value >>= aVal) ) + SAL_WARN("connectivity.flat", "construct: unable to get property StringDelimiter"); + + m_cStringDelimiter = aVal.toChar(); + } + else if(pBegin->Name == "DecimalDelimiter") + { + OUString aVal; + if( ! (pBegin->Value >>= aVal) ) + SAL_WARN("connectivity.flat", "construct: unable to get property DecimalDelimiter"); + + m_cDecimalDelimiter = aVal.toChar(); + } + else if(pBegin->Name == "ThousandDelimiter") + { + OUString aVal; + if( ! (pBegin->Value >>= aVal) ) + SAL_WARN("connectivity.flat", "construct: unable to get property ThousandDelimiter"); + + m_cThousandDelimiter = aVal.toChar(); + } + else if ( pBegin->Name == "MaxRowScan" ) + { + pBegin->Value >>= m_nMaxRowsToScan; + } + } + + osl_atomic_decrement( &m_refCount ); + OConnection::construct(url,info); + m_bShowDeleted = true; // we do not supported rows for this type +} + +Reference< XDatabaseMetaData > SAL_CALL OFlatConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_B::rBHelper.bDisposed); + + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new OFlatDatabaseMetaData(this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +css::uno::Reference< XTablesSupplier > OFlatConnection::createCatalog() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XTablesSupplier > xTab = m_xCatalog; + if(!xTab.is()) + { + OFlatCatalog *pCat = new OFlatCatalog(this); + xTab = pCat; + m_xCatalog = xTab; + } + return xTab; +} + +Reference< XStatement > SAL_CALL OFlatConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_B::rBHelper.bDisposed); + + OFlatStatement* pStmt = new OFlatStatement(this); + + Reference< XStatement > xStmt = pStmt; + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return xStmt; +} + +Reference< XPreparedStatement > SAL_CALL OFlatConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_B::rBHelper.bDisposed); + + + OFlatPreparedStatement* pStmt = new OFlatPreparedStatement(this); + Reference< XPreparedStatement > xStmt = pStmt; + pStmt->construct(sql); + + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return xStmt; +} + +Reference< XPreparedStatement > SAL_CALL OFlatConnection::prepareCall( const OUString& /*sql*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_B::rBHelper.bDisposed); + + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this ); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EDatabaseMetaData.cxx b/connectivity/source/drivers/flat/EDatabaseMetaData.cxx new file mode 100644 index 000000000..b69b34e36 --- /dev/null +++ b/connectivity/source/drivers/flat/EDatabaseMetaData.cxx @@ -0,0 +1,245 @@ +/* -*- 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 <flat/EDatabaseMetaData.hxx> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <FDatabaseMetaDataResultSet.hxx> +#include <comphelper/types.hxx> + +using namespace ::comphelper; + +using namespace connectivity; +using namespace connectivity::flat; +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; + + +OFlatDatabaseMetaData::OFlatDatabaseMetaData(::connectivity::file::OConnection* _pCon) :ODatabaseMetaData(_pCon) +{ +} + +OFlatDatabaseMetaData::~OFlatDatabaseMetaData() +{ +} + +Reference< XResultSet > OFlatDatabaseMetaData::impl_getTypeInfo_throw( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo); + Reference< XResultSet > xRef = pResult; + + static ODatabaseMetaDataResultSet::ORows aRows = [&]() + { + ODatabaseMetaDataResultSet::ORows tmp; + ODatabaseMetaDataResultSet::ORow aRow; + + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(OUString("CHAR"))); + aRow.push_back(new ORowSetValueDecorator(DataType::CHAR)); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(254))); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(ColumnValue::NULLABLE))); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR))); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(10))); + + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::VARCHAR); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + + aRow[1] = new ORowSetValueDecorator(OUString("LONGVARCHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::LONGVARCHAR); + aRow[3] = new ORowSetValueDecorator(sal_Int32(65535)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DATE")); + aRow[2] = new ORowSetValueDecorator(DataType::DATE); + aRow[3] = new ORowSetValueDecorator(sal_Int32(10)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("TIME")); + aRow[2] = new ORowSetValueDecorator(DataType::TIME); + aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP")); + aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP); + aRow[3] = new ORowSetValueDecorator(sal_Int32(19)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("BOOL")); + aRow[2] = new ORowSetValueDecorator(DataType::BIT); + aRow[3] = ODatabaseMetaDataResultSet::get1Value(); + aRow[9] = ODatabaseMetaDataResultSet::getBasicValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL")); + aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[15] = new ORowSetValueDecorator(sal_Int32(15)); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE")); + aRow[2] = new ORowSetValueDecorator(DataType::DOUBLE); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC")); + aRow[2] = new ORowSetValueDecorator(DataType::NUMERIC); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[15] = new ORowSetValueDecorator(sal_Int32(20)); + tmp.push_back(aRow); + + return tmp; + }(); + + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL OFlatDatabaseMetaData::getColumns( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XTablesSupplier > xTables = m_pConnection->createCatalog(); + if(!xTables.is()) + throw SQLException(); + + Reference< XNameAccess> xNames = xTables->getTables(); + if(!xNames.is()) + throw SQLException(); + + ODatabaseMetaDataResultSet::ORows aRows; + ODatabaseMetaDataResultSet::ORow aRow(19); + aRow[10] = new ORowSetValueDecorator(sal_Int32(10)); + Sequence< OUString> aTabNames(xNames->getElementNames()); + const OUString* pTabBegin = aTabNames.getConstArray(); + const OUString* pTabEnd = pTabBegin + aTabNames.getLength(); + for(;pTabBegin != pTabEnd;++pTabBegin) + { + if(match(tableNamePattern,*pTabBegin,'\0')) + { + Reference< XColumnsSupplier> xTable( + xNames->getByName(*pTabBegin), css::uno::UNO_QUERY); + aRow[3] = new ORowSetValueDecorator(*pTabBegin); + + Reference< XNameAccess> xColumns = xTable->getColumns(); + if(!xColumns.is()) + throw SQLException(); + + Sequence< OUString> aColNames(xColumns->getElementNames()); + + const OUString* pBegin = aColNames.getConstArray(); + const OUString* pEnd = pBegin + aColNames.getLength(); + Reference< XPropertySet> xColumn; + for(sal_Int32 i=1;pBegin != pEnd;++pBegin,++i) + { + if(match(columnNamePattern,*pBegin,'\0')) + { + aRow[4] = new ORowSetValueDecorator(*pBegin); + + xColumn.set( + xColumns->getByName(*pBegin), css::uno::UNO_QUERY); + OSL_ENSURE(xColumn.is(),"Columns contains a column who isn't a fastpropertyset!"); + aRow[5] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))); + aRow[6] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))); + aRow[7] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))); + aRow[9] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))); + aRow[11] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))); + aRow[13] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))); + + switch(static_cast<sal_Int32>(aRow[5]->getValue())) + { + case DataType::CHAR: + case DataType::VARCHAR: + aRow[16] = new ORowSetValueDecorator(sal_Int32(254)); + break; + case DataType::LONGVARCHAR: + aRow[16] = new ORowSetValueDecorator(sal_Int32(65535)); + break; + default: + aRow[16] = new ORowSetValueDecorator(sal_Int32(0)); + } + aRow[17] = new ORowSetValueDecorator(i); + switch(sal_Int32(aRow[11]->getValue())) + { + case ColumnValue::NO_NULLS: + aRow[18] = new ORowSetValueDecorator(OUString("NO")); + break; + case ColumnValue::NULLABLE: + aRow[18] = new ORowSetValueDecorator(OUString("YES")); + break; + default: + aRow[18] = new ORowSetValueDecorator(OUString()); + } + aRows.push_back(aRow); + } + } + } + } + + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns); + Reference< XResultSet > xRef = pResult; + pResult->setRows(aRows); + + return xRef; +} + +OUString SAL_CALL OFlatDatabaseMetaData::getURL( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return "sdbc:flat:" + m_pConnection->getURL(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EDriver.cxx b/connectivity/source/drivers/flat/EDriver.cxx new file mode 100644 index 000000000..e10f29da7 --- /dev/null +++ b/connectivity/source/drivers/flat/EDriver.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <flat/EDriver.hxx> +#include <flat/EConnection.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <connectivity/dbexception.hxx> +#include <comphelper/sequence.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> +#include <comphelper/processfactory.hxx> + + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace css::uno; +using namespace css::beans; +using namespace css::sdbcx; +using namespace css::sdbc; +using namespace css::lang; + + +// static ServiceInfo + +OUString ODriver::getImplementationName_Static( ) +{ + return "com.sun.star.comp.sdbc.flat.ODriver"; +} + + +OUString SAL_CALL ODriver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + + +css::uno::Reference< css::uno::XInterface > connectivity::flat::ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory) +{ + return *(new ODriver( comphelper::getComponentContext(_rxFactory) )); +} + +Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url, const Sequence< PropertyValue >& info ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (ODriver_BASE::rBHelper.bDisposed) + throw DisposedException(); + + if ( ! acceptsURL(url) ) + return nullptr; + + OFlatConnection* pCon = new OFlatConnection(this); + pCon->construct(url,info); + Reference< XConnection > xCon = pCon; + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + + return xCon; +} + +sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url ) +{ + return url.startsWith("sdbc:flat:"); +} + +Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& info ) +{ + if ( acceptsURL(url) ) + { + std::vector< DriverPropertyInfo > aDriverInfo; + + Sequence< OUString > aBoolean(2); + aBoolean[0] = "0"; + aBoolean[1] = "1"; + + aDriverInfo.push_back(DriverPropertyInfo( + "FieldDelimiter" + ,"Field separator." + ,false + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "HeaderLine" + ,"Text contains headers." + ,false + ,"0" + ,aBoolean) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "StringDelimiter" + ,"Text separator." + ,false + ,"0" + ,aBoolean) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "DecimalDelimiter" + ,"Decimal separator." + ,false + ,"0" + ,aBoolean) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "ThousandDelimiter" + ,"Thousands separator." + ,false + ,"0" + ,aBoolean) + ); + return ::comphelper::concatSequences(OFileDriver::getPropertyInfo(url,info ), + Sequence< DriverPropertyInfo >(aDriverInfo.data(),aDriverInfo.size())); + } + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + return Sequence< DriverPropertyInfo >(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EPreparedStatement.cxx b/connectivity/source/drivers/flat/EPreparedStatement.cxx new file mode 100644 index 000000000..64a0b3a1c --- /dev/null +++ b/connectivity/source/drivers/flat/EPreparedStatement.cxx @@ -0,0 +1,35 @@ +/* -*- 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 <flat/EPreparedStatement.hxx> +#include <flat/EResultSet.hxx> + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace ::com::sun::star::uno; + +OResultSet* OFlatPreparedStatement::createResultSet() +{ + return new OFlatResultSet(this,m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(OFlatPreparedStatement,"com.sun.star.sdbc.driver.flat.PreparedStatement","com.sun.star.sdbc.PreparedStatement"); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EResultSet.cxx b/connectivity/source/drivers/flat/EResultSet.cxx new file mode 100644 index 000000000..aca803041 --- /dev/null +++ b/connectivity/source/drivers/flat/EResultSet.cxx @@ -0,0 +1,169 @@ +/* -*- 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 <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <flat/EResultSet.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace ::comphelper; + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace ::cppu; +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::sdbcx; + + +OFlatResultSet::OFlatResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator) + : file::OResultSet(pStmt,_aSQLIterator) + ,m_bBookmarkable(true) +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), PROPERTY_ID_ISBOOKMARKABLE, PropertyAttribute::READONLY,&m_bBookmarkable, cppu::UnoType<bool>::get()); +} + +OUString SAL_CALL OFlatResultSet::getImplementationName( ) +{ + return "com.sun.star.sdbcx.flat.ResultSet"; +} + +Sequence< OUString > SAL_CALL OFlatResultSet::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL OFlatResultSet::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Any SAL_CALL OFlatResultSet::queryInterface( const Type & rType ) +{ + if(rType == cppu::UnoType<XDeleteRows>::get()|| rType == cppu::UnoType<XResultSetUpdate>::get() + || rType == cppu::UnoType<XRowUpdate>::get()) + return Any(); + + const Any aRet = OResultSet::queryInterface(rType); + return aRet.hasValue() ? aRet : OFlatResultSet_BASE::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OFlatResultSet::getTypes( ) +{ + Sequence< Type > aTypes = OResultSet::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!(*pBegin == cppu::UnoType<XDeleteRows>::get()|| + *pBegin == cppu::UnoType<XResultSetUpdate>::get()|| + *pBegin == cppu::UnoType<XRowUpdate>::get())) + { + aOwnTypes.push_back(*pBegin); + } + } + Sequence< Type > aRet(aOwnTypes.data(), aOwnTypes.size()); + return ::comphelper::concatSequences(aRet,OFlatResultSet_BASE::getTypes()); +} + + +// XRowLocate +Any SAL_CALL OFlatResultSet::getBookmark( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return makeAny(static_cast<sal_Int32>((*m_aRow)[0]->getValue())); +} + +sal_Bool SAL_CALL OFlatResultSet::moveToBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false; + + return Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),true); +} + +sal_Bool SAL_CALL OFlatResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false; + + Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),false); + + return relative(rows); +} + + +sal_Int32 SAL_CALL OFlatResultSet::compareBookmarks( const Any& lhs, const Any& rhs ) +{ + return (lhs == rhs) ? CompareBookmark::EQUAL : CompareBookmark::NOT_EQUAL; +} + +sal_Bool SAL_CALL OFlatResultSet::hasOrderedBookmarks( ) +{ + return true; +} + +sal_Int32 SAL_CALL OFlatResultSet::hashBookmark( const Any& bookmark ) +{ + return comphelper::getINT32(bookmark); +} + +IPropertyArrayHelper* OFlatResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +IPropertyArrayHelper & OFlatResultSet::getInfoHelper() +{ + return *OFlatResultSet_BASE3::getArrayHelper(); +} + +void SAL_CALL OFlatResultSet::acquire() throw() +{ + OFlatResultSet_BASE2::acquire(); +} + +void SAL_CALL OFlatResultSet::release() throw() +{ + OFlatResultSet_BASE2::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OFlatResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EStatement.cxx b/connectivity/source/drivers/flat/EStatement.cxx new file mode 100644 index 000000000..777463905 --- /dev/null +++ b/connectivity/source/drivers/flat/EStatement.cxx @@ -0,0 +1,34 @@ +/* -*- 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 <flat/EStatement.hxx> +#include <flat/EResultSet.hxx> + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace css::uno; + +OResultSet* OFlatStatement::createResultSet() +{ + return new OFlatResultSet(this,m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(OFlatStatement,"com.sun.star.sdbc.driver.flat.Statement","com.sun.star.sdbc.Statement"); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/ETable.cxx b/connectivity/source/drivers/flat/ETable.cxx new file mode 100644 index 000000000..0dceba05b --- /dev/null +++ b/connectivity/source/drivers/flat/ETable.cxx @@ -0,0 +1,964 @@ +/* -*- 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 <flat/ETable.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <flat/EConnection.hxx> +#include <flat/EColumns.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/math.hxx> +#include <sal/log.hxx> +#include <tools/solar.h> +#include <tools/urlobj.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/numbers.hxx> +#include <comphelper/servicehelper.hxx> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/util/NumberFormatsSupplier.hpp> +#include <i18nlangtag/languagetag.hxx> +#include <connectivity/dbconversion.hxx> +#include <connectivity/sdbcx/VColumn.hxx> +#include <file/quotedstring.hxx> +#include <file/FDriver.hxx> +#include <unotools/syslocale.hxx> +#include <unotools/charclass.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +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 ::com::sun::star::util; +using std::vector; +using std::lower_bound; + + +void OFlatTable::fillColumns(const css::lang::Locale& _aLocale) +{ + m_bNeedToReadLine = true; // we overwrite m_aCurrentLine, seek the stream, ... + m_pFileStream->Seek(0); + m_aCurrentLine = QuotedTokenizedString(); + bool bRead = true; + + const OFlatConnection* const pConnection = getFlatConnection(); + const bool bHasHeaderLine = pConnection->isHeaderLine(); + + QuotedTokenizedString aHeaderLine; + TRowPositionInFile rowPos(0, 0); + sal_Int32 rowNum(0); + if ( bHasHeaderLine ) + { + bRead = readLine(&rowPos.second, &rowPos.first, true); + if(bRead) + aHeaderLine = m_aCurrentLine; + } + setRowPos(rowNum++, rowPos); + + // read first row + if(bRead) + { + bRead = readLine(&rowPos.second, &rowPos.first); + if(bRead) + setRowPos(rowNum++, rowPos); + } + + if ( !bHasHeaderLine || !aHeaderLine.Len()) + { + // use first non-empty row as headerline because we need the number of columns + while(bRead && m_aCurrentLine.Len() == 0) + { + bRead = readLine(&rowPos.second, &rowPos.first); + if(bRead) + setRowPos(rowNum++, rowPos); + } + aHeaderLine = m_aCurrentLine; + } + // column count + const sal_Int32 nFieldCount = aHeaderLine.GetTokenCount(m_cFieldDelimiter,m_cStringDelimiter); + + if(!m_aColumns.is()) + m_aColumns = new OSQLColumns(); + else + m_aColumns->clear(); + + m_aTypes.clear(); + m_aPrecisions.clear(); + m_aScales.clear(); + // reserve some space + m_aColumns->reserve(nFieldCount+1); + m_aTypes.assign(nFieldCount+1,DataType::SQLNULL); + m_aPrecisions.assign(nFieldCount+1,-1); + m_aScales.assign(nFieldCount+1,-1); + + const bool bCase = m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers(); + CharClass aCharClass( pConnection->getDriver()->getComponentContext(), LanguageTag( _aLocale)); + // read description + const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); + const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); + ::comphelper::UStringMixEqual aCase(bCase); + vector<OUString> aColumnNames; + vector<OUString> aTypeNames; + aTypeNames.resize(nFieldCount); + const sal_Int32 nMaxRowsToScan = pConnection->getMaxRowsToScan(); + sal_Int32 nRowCount = 0; + + do + { + sal_Int32 nStartPosHeaderLine = 0; // use for efficient way to get the tokens + sal_Int32 nStartPosFirstLine = 0; // use for efficient way to get the tokens + sal_Int32 nStartPosFirstLine2 = 0; + for( sal_Int32 i = 0; i < nFieldCount; i++ ) + { + if ( nRowCount == 0) + { + OUString aColumnName; + if ( bHasHeaderLine ) + { + aColumnName = aHeaderLine.GetTokenSpecial(nStartPosHeaderLine,m_cFieldDelimiter,m_cStringDelimiter); + } + if ( aColumnName.isEmpty() ) + { + aColumnName = "C" + OUString::number(i+1); + } + aColumnNames.push_back(aColumnName); + } + if(bRead) + { + impl_fillColumnInfo_nothrow(m_aCurrentLine, nStartPosFirstLine, nStartPosFirstLine2, + m_aTypes[i], m_aPrecisions[i], m_aScales[i], aTypeNames[i], + cDecimalDelimiter, cThousandDelimiter, aCharClass); + } + } + ++nRowCount; + bRead = readLine(&rowPos.second, &rowPos.first); + if(bRead) + setRowPos(rowNum++, rowPos); + } + while(nRowCount < nMaxRowsToScan && bRead); + + for( sal_Int32 i = 0; i < nFieldCount; i++ ) + { + // check if the columname already exists + OUString aAlias(aColumnNames[i]); + OSQLColumns::const_iterator aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase); + sal_Int32 nExprCnt = 0; + while(aFind != m_aColumns->end()) + { + aAlias = aColumnNames[i] + OUString::number(++nExprCnt); + aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase); + } + + sdbcx::OColumn* pColumn = new sdbcx::OColumn(aAlias,aTypeNames[i],OUString(),OUString(), + ColumnValue::NULLABLE, + m_aPrecisions[i], + m_aScales[i], + m_aTypes[i], + false, + false, + false, + bCase, + m_CatalogName, getSchema(), getName()); + Reference< XPropertySet> xCol = pColumn; + m_aColumns->push_back(xCol); + } + + m_pFileStream->Seek(m_aRowPosToFilePos[0].second); +} + +void OFlatTable::impl_fillColumnInfo_nothrow(QuotedTokenizedString const & aFirstLine, sal_Int32& nStartPosFirstLine, sal_Int32& nStartPosFirstLine2, + sal_Int32& io_nType, sal_Int32& io_nPrecisions, sal_Int32& io_nScales, OUString& o_sTypeName, + const sal_Unicode cDecimalDelimiter, const sal_Unicode cThousandDelimiter, const CharClass& aCharClass) +{ + if ( io_nType != DataType::VARCHAR ) + { + bool bNumeric = io_nType == DataType::SQLNULL || io_nType == DataType::DOUBLE || io_nType == DataType::DECIMAL || io_nType == DataType::INTEGER; + sal_uLong nIndex = 0; + + if ( bNumeric ) + { + // first without fielddelimiter + OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter); + if (aField.isEmpty() || + (m_cStringDelimiter && m_cStringDelimiter == aField[0])) + { + bNumeric = false; + if ( m_cStringDelimiter != '\0' ) + aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); + else + nStartPosFirstLine2 = nStartPosFirstLine; + } + else + { + OUString aField2; + if ( m_cStringDelimiter != '\0' ) + aField2 = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); + else + aField2 = aField; + + if (aField2.isEmpty()) + { + bNumeric = false; + } + else + { + bNumeric = true; + sal_Int32 nDot = 0; + sal_Int32 nDecimalDelCount = 0; + sal_Int32 nSpaceCount = 0; + for( sal_Int32 j = 0; j < aField2.getLength(); j++ ) + { + const sal_Unicode c = aField2[j]; + if ( j == nSpaceCount && m_cFieldDelimiter != 32 && c == 32 ) + { + ++nSpaceCount; + continue; + } + // just digits, decimal- and thousands-delimiter? + if ( ( !cDecimalDelimiter || c != cDecimalDelimiter ) && + ( !cThousandDelimiter || c != cThousandDelimiter ) && + !aCharClass.isDigit(aField2,j) && + ( j != 0 || (c != '+' && c != '-' ) ) ) + { + bNumeric = false; + break; + } + if (cDecimalDelimiter && c == cDecimalDelimiter) + { + io_nPrecisions = 15; // we have a decimal value + io_nScales = 2; + ++nDecimalDelCount; + } // if (cDecimalDelimiter && c == cDecimalDelimiter) + if ( c == '.' ) + ++nDot; + } + + if (nDecimalDelCount > 1 || nDot > 1 ) // if there is more than one dot it isn't a number + bNumeric = false; + if (bNumeric && cThousandDelimiter) + { + // Is the delimiter correct? + const OUString aValue = aField2.getToken(0,cDecimalDelimiter); + for( sal_Int32 j = aValue.getLength() - 4; j >= 0; j -= 4) + { + const sal_Unicode c = aValue[j]; + // just digits, decimal- and thousands-delimiter? + if (c == cThousandDelimiter && j) + continue; + else + { + bNumeric = false; + break; + } + } + } + + // now also check for a date field + if (!bNumeric) + { + try + { + nIndex = m_xNumberFormatter->detectNumberFormat(css::util::NumberFormat::ALL,aField2); + } + catch(Exception&) + { + } + } + } + } + } + else if ( io_nType == DataType::DATE || io_nType == DataType::TIMESTAMP || io_nType == DataType::TIME) + { + OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter); + if (aField.isEmpty() || + (m_cStringDelimiter && m_cStringDelimiter == aField[0])) + { + } + else + { + OUString aField2; + if ( m_cStringDelimiter != '\0' ) + aField2 = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); + else + aField2 = aField; + if (!aField2.isEmpty() ) + { + try + { + nIndex = m_xNumberFormatter->detectNumberFormat(css::util::NumberFormat::ALL,aField2); + } + catch(Exception&) + { + } + } + } + } + + if (bNumeric) + { + if (cDecimalDelimiter) + { + if(io_nPrecisions) + { + io_nType = DataType::DECIMAL; + o_sTypeName = "DECIMAL"; + } + else + { + io_nType = DataType::DOUBLE; + o_sTypeName = "DOUBLE"; + } + } + else + { + io_nType = DataType::INTEGER; + io_nPrecisions = 0; + io_nScales = 0; + } + } + else + { + switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex)) + { + case css::util::NumberFormat::DATE: + io_nType = DataType::DATE; + o_sTypeName = "DATE"; + break; + case css::util::NumberFormat::DATETIME: + io_nType = DataType::TIMESTAMP; + o_sTypeName = "TIMESTAMP"; + break; + case css::util::NumberFormat::TIME: + io_nType = DataType::TIME; + o_sTypeName = "TIME"; + break; + default: + io_nType = DataType::VARCHAR; + io_nPrecisions = 0; // nyi: Data can be longer! + io_nScales = 0; + o_sTypeName = "VARCHAR"; + }; + } + } + else + { + OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter); + if (aField.isEmpty() || + (m_cStringDelimiter && m_cStringDelimiter == aField[0])) + { + if ( m_cStringDelimiter != '\0' ) + aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine2, m_cFieldDelimiter, m_cStringDelimiter); + else + nStartPosFirstLine2 = nStartPosFirstLine; + } + else + { + if ( m_cStringDelimiter != '\0' ) + aFirstLine.GetTokenSpecial(nStartPosFirstLine2, m_cFieldDelimiter, m_cStringDelimiter); + } + } +} + +OFlatTable::OFlatTable(sdbcx::OCollection* _pTables,OFlatConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName + ) : OFlatTable_BASE(_pTables,_pConnection,Name, + Type, + Description, + SchemaName, + CatalogName) + ,m_nRowPos(0) + ,m_nMaxRowCount(0) + ,m_cStringDelimiter(_pConnection->getStringDelimiter()) + ,m_cFieldDelimiter(_pConnection->getFieldDelimiter()) + ,m_bNeedToReadLine(false) +{ + +} + +void OFlatTable::construct() +{ + SvtSysLocale aLocale; + css::lang::Locale aAppLocale(aLocale.GetLanguageTag().getLocale()); + + Reference< XNumberFormatsSupplier > xSupplier = NumberFormatsSupplier::createWithLocale( m_pConnection->getDriver()->getComponentContext(), aAppLocale ); + m_xNumberFormatter.set( NumberFormatter::create( m_pConnection->getDriver()->getComponentContext()), UNO_QUERY_THROW); + m_xNumberFormatter->attachNumberFormatsSupplier(xSupplier); + Reference<XPropertySet> xProp = xSupplier->getNumberFormatSettings(); + xProp->getPropertyValue("NullDate") >>= m_aNullDate; + + INetURLObject aURL; + aURL.SetURL(getEntry()); + + if(aURL.getExtension() != m_pConnection->getExtension()) + aURL.setExtension(m_pConnection->getExtension()); + + OUString aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + + m_pFileStream = createStream_simpleError( aFileName, StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE); + + if(!m_pFileStream) + m_pFileStream = createStream_simpleError( aFileName, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE); + + if(!m_pFileStream) + return; + + sal_uInt64 const nSize = m_pFileStream->remainingSize(); + + // Buffersize is dependent on the file-size + m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 : + nSize > 100000 ? 16384 : + nSize > 10000 ? 4096 : 1024); + + fillColumns(aAppLocale); + + refreshColumns(); +} + +OUString OFlatTable::getEntry() const +{ + OUString sURL; + try + { + Reference< XResultSet > xDir = m_pConnection->getDir()->getStaticResultSet(); + Reference< XRow> xRow(xDir,UNO_QUERY); + OUString sName; + OUString sExt; + + INetURLObject aURL; + xDir->beforeFirst(); + while(xDir->next()) + { + sName = xRow->getString(1); + aURL.SetSmartProtocol(INetProtocol::File); + OUString sUrl = m_pConnection->getURL() + "/" + sName; + aURL.SetSmartURL( sUrl ); + + // cut the extension + sExt = aURL.getExtension(); + + // name and extension have to coincide + if ( m_pConnection->matchesExtension( sExt ) ) + { + if ( !sExt.isEmpty() ) + sName = sName.replaceAt(sName.getLength() - (sExt.getLength() + 1), sExt.getLength()+1, OUString()); + if ( sName == m_Name ) + { + Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY ); + sURL = xContentAccess->queryContentIdentifierString(); + break; + } + } + } + xDir->beforeFirst(); // move back to before first record + } + catch(const Exception&) + { + OSL_ASSERT(false); + } + return sURL; +} + +void OFlatTable::refreshColumns() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::std::vector< OUString> aVector; + aVector.reserve(m_aColumns->size()); + + for (auto const& column : *m_aColumns) + aVector.push_back(Reference< XNamed>(column,UNO_QUERY_THROW)->getName()); + + if(m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns = new OFlatColumns(this,m_aMutex,aVector); +} + + +void SAL_CALL OFlatTable::disposing() +{ + OFileTable::disposing(); + ::osl::MutexGuard aGuard(m_aMutex); + m_aColumns = nullptr; +} + +Sequence< Type > SAL_CALL OFlatTable::getTypes( ) +{ + Sequence< Type > aTypes = OTable_TYPEDEF::getTypes(); + vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(!(*pBegin == cppu::UnoType<XKeysSupplier>::get()|| + *pBegin == cppu::UnoType<XRename>::get()|| + *pBegin == cppu::UnoType<XIndexesSupplier>::get()|| + *pBegin == cppu::UnoType<XAlterTable>::get()|| + *pBegin == cppu::UnoType<XDataDescriptorFactory>::get())) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +Any SAL_CALL OFlatTable::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType<XKeysSupplier>::get()|| + rType == cppu::UnoType<XIndexesSupplier>::get()|| + rType == cppu::UnoType<XRename>::get()|| + rType == cppu::UnoType<XAlterTable>::get()|| + rType == cppu::UnoType<XDataDescriptorFactory>::get()) + return Any(); + + Any aRet = OTable_TYPEDEF::queryInterface(rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< css::lang::XUnoTunnel*> (this)); +} + + +Sequence< sal_Int8 > OFlatTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OFlatTable::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return (isUnoTunnelId<OFlatTable>(rId)) + ? reinterpret_cast< sal_Int64 >( this ) + : OFlatTable_BASE::getSomething(rId); +} + +bool OFlatTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns & _rCols, bool bRetrieveData) +{ + *(*_rRow)[0] = m_nFilePos; + + if (!bRetrieveData) + return true; + + bool result = false; + if ( m_bNeedToReadLine ) + { + m_pFileStream->Seek(m_nFilePos); + TRowPositionInFile rowPos(0, 0); + if(readLine(&rowPos.second, &rowPos.first)) + { + setRowPos(m_nRowPos, rowPos); + m_bNeedToReadLine = false; + result = true; + } + // else let run through so that we set _rRow to all NULL + } + + const OFlatConnection * const pConnection = getFlatConnection(); + const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); + const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); + // Fields: + sal_Int32 nStartPos = 0; + OSQLColumns::const_iterator aIter = _rCols.begin(); + OSQLColumns::const_iterator aEnd = _rCols.end(); + const OValueRefVector::size_type nCount = _rRow->size(); + for (OValueRefVector::size_type i = 1; + aIter != aEnd && i < nCount; + ++aIter, i++) + { + OUString aStr = m_aCurrentLine.GetTokenSpecial(nStartPos,m_cFieldDelimiter,m_cStringDelimiter); + + if (aStr.isEmpty()) + { + (*_rRow)[i]->setNull(); + } + else + { + sal_Int32 nType = m_aTypes[i-1]; + switch(nType) + { + case DataType::TIMESTAMP: + case DataType::DATE: + case DataType::TIME: + { + try + { + double nRes = m_xNumberFormatter->convertStringToNumber(css::util::NumberFormat::ALL,aStr); + + switch(nType) + { + case DataType::DATE: + *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes,m_aNullDate)); + break; + case DataType::TIMESTAMP: + *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes,m_aNullDate)); + break; + default: + *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes)); + } + } + catch(Exception&) + { + (*_rRow)[i]->setNull(); + } + } break; + case DataType::DOUBLE: + case DataType::INTEGER: + case DataType::DECIMAL: + case DataType::NUMERIC: + { + + OUString aStrConverted; + if ( DataType::INTEGER != nType ) + { + OSL_ENSURE((cDecimalDelimiter && nType != DataType::INTEGER) || + (!cDecimalDelimiter && nType == DataType::INTEGER), + "Wrong type"); + + OUStringBuffer aBuf(aStr.getLength()); + // convert to Standard-Notation (DecimalPOINT without thousands-comma): + for (sal_Int32 j = 0; j < aStr.getLength(); ++j) + { + const sal_Unicode cChar = aStr[j]; + if (cDecimalDelimiter && cChar == cDecimalDelimiter) + aBuf.append('.'); + else if ( cChar == '.' ) // special case, if decimal separator isn't '.' we have to put the string after it + continue; + else if (cThousandDelimiter && cChar == cThousandDelimiter) + { + // leave out + } + else + aBuf.append(cChar); + } // for (j = 0; j < aStr.(); ++j) + aStrConverted = aBuf.makeStringAndClear(); + } // if ( DataType::INTEGER != nType ) + else + { + if ( cThousandDelimiter ) + aStrConverted = aStr.replaceAll(OUStringChar(cThousandDelimiter), ""); + else + aStrConverted = aStr; + } + const double nVal = ::rtl::math::stringToDouble(aStrConverted,'.',','); + + // #99178# OJ + if ( DataType::DECIMAL == nType || DataType::NUMERIC == nType ) + *(*_rRow)[i] = OUString(OUString::number(nVal)); + else + *(*_rRow)[i] = nVal; + } break; + + default: + { + // Copy Value as String in Row-Variable + *(*_rRow)[i] = ORowSetValue(aStr); + } + break; + } // switch(nType) + (*_rRow)[i]->setTypeKind(nType); + } + } + return result; +} + + +void OFlatTable::refreshHeader() +{ + SAL_INFO( "connectivity.flat", "flat lionel@mamane.lu OFlatTable::refreshHeader" ); +} + + +namespace +{ + template< typename Tp, typename Te> struct RangeBefore + { + bool operator() (const Tp &p, const Te &e) + { + assert(p.first <= p.second); + return p.second <= e; + } + }; +} + +bool OFlatTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) +{ + OSL_ENSURE(m_pFileStream,"OFlatTable::seekRow: FileStream is NULL!"); + + + switch(eCursorPosition) + { + case IResultSetHelper::FIRST: + m_nRowPos = 0; + [[fallthrough]]; + case IResultSetHelper::NEXT: + { + assert(m_nRowPos >= 0); + if(m_nMaxRowCount != 0 && m_nRowPos > m_nMaxRowCount) + return false; + ++m_nRowPos; + if(m_aRowPosToFilePos.size() > o3tl::make_unsigned(m_nRowPos)) + { + m_bNeedToReadLine = true; + m_nFilePos = m_aRowPosToFilePos[m_nRowPos].first; + nCurPos = m_aRowPosToFilePos[m_nRowPos].second; + } + else + { + assert(m_aRowPosToFilePos.size() == static_cast< vector< TRowPositionInFile >::size_type >(m_nRowPos)); + const TRowPositionInFile &lastRowPos(m_aRowPosToFilePos.back()); + // Our ResultSet is allowed to disagree with us only + // on the position of the first line + // (because of the special case of the header...) + assert(m_nRowPos == 1 || nCurPos == lastRowPos.second); + + m_nFilePos = lastRowPos.second; + m_pFileStream->Seek(m_nFilePos); + + TRowPositionInFile newRowPos; + if(!readLine(&newRowPos.second, &newRowPos.first)) + { + m_nMaxRowCount = m_nRowPos - 1; + return false; + } + + nCurPos = newRowPos.second; + setRowPos(m_nRowPos, newRowPos); + } + } + + break; + case IResultSetHelper::PRIOR: + assert(m_nRowPos >= 0); + + if(m_nRowPos == 0) + return false; + + --m_nRowPos; + { + assert (m_nRowPos >= 0); + assert(m_aRowPosToFilePos.size() >= o3tl::make_unsigned(m_nRowPos)); + const TRowPositionInFile &aPositions(m_aRowPosToFilePos[m_nRowPos]); + m_nFilePos = aPositions.first; + nCurPos = aPositions.second; + m_bNeedToReadLine = true; + } + + break; + case IResultSetHelper::LAST: + if (m_nMaxRowCount == 0) + { + while(seekRow(IResultSetHelper::NEXT, 1, nCurPos)) ; // run through after last row + } + // m_nMaxRowCount can still be zero, but now it means there a genuinely zero rows in the table + return seekRow(IResultSetHelper::ABSOLUTE1, m_nMaxRowCount, nCurPos); + break; + case IResultSetHelper::RELATIVE1: + { + const sal_Int32 nNewRowPos = m_nRowPos + nOffset; + if (nNewRowPos < 0) + return false; + // ABSOLUTE will take care of case nNewRowPos > nMaxRowCount + return seekRow(IResultSetHelper::ABSOLUTE1, nNewRowPos, nCurPos); + } + case IResultSetHelper::ABSOLUTE1: + { + if(nOffset < 0) + { + if (m_nMaxRowCount == 0) + { + if (!seekRow(IResultSetHelper::LAST, 0, nCurPos)) + return false; + } + // m_nMaxRowCount can still be zero, but now it means there a genuinely zero rows in the table + nOffset = m_nMaxRowCount + nOffset; + } + if(nOffset < 0) + { + seekRow(IResultSetHelper::ABSOLUTE1, 0, nCurPos); + return false; + } + if(m_nMaxRowCount && nOffset > m_nMaxRowCount) + { + m_nRowPos = m_nMaxRowCount + 1; + const TRowPositionInFile &lastRowPos(m_aRowPosToFilePos.back()); + m_nFilePos = lastRowPos.second; + nCurPos = lastRowPos.second; + return false; + } + + assert(m_nRowPos >=0); + assert(m_aRowPosToFilePos.size() > o3tl::make_unsigned(m_nRowPos)); + assert(nOffset >= 0); + if(m_aRowPosToFilePos.size() > o3tl::make_unsigned(nOffset)) + { + m_nFilePos = m_aRowPosToFilePos[nOffset].first; + nCurPos = m_aRowPosToFilePos[nOffset].second; + m_nRowPos = nOffset; + m_bNeedToReadLine = true; + } + else + { + assert(m_nRowPos < nOffset); + while(m_nRowPos < nOffset) + { + if(!seekRow(IResultSetHelper::NEXT, 1, nCurPos)) + return false; + } + assert(m_nRowPos == nOffset); + } + } + + break; + case IResultSetHelper::BOOKMARK: + { + vector< TRowPositionInFile >::const_iterator aFind = lower_bound(m_aRowPosToFilePos.begin(), + m_aRowPosToFilePos.end(), + nOffset, + RangeBefore< TRowPositionInFile, sal_Int32 >()); + + if(aFind == m_aRowPosToFilePos.end() || aFind->first != nOffset) + //invalid bookmark + return false; + + m_bNeedToReadLine = true; + m_nFilePos = aFind->first; + nCurPos = aFind->second; + m_nRowPos = aFind - m_aRowPosToFilePos.begin(); + break; + } + } + + return true; +} + + +bool OFlatTable::readLine(sal_Int32 * const pEndPos, sal_Int32 * const pStartPos, const bool nonEmpty) +{ + const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding(); + m_aCurrentLine = QuotedTokenizedString(); + do + { + if (pStartPos) + *pStartPos = static_cast<sal_Int32>(m_pFileStream->Tell()); + m_pFileStream->ReadByteStringLine(m_aCurrentLine, nEncoding); + if (m_pFileStream->eof()) + return false; + + QuotedTokenizedString sLine = m_aCurrentLine; // check if the string continues on next line + sal_Int32 nLastOffset = 0; + bool isQuoted = false; + bool isFieldStarting = true; + while (true) + { + bool wasQuote = false; + const sal_Unicode *p = sLine.GetString().getStr() + nLastOffset; + while (*p) + { + if (isQuoted) + { + if (*p == m_cStringDelimiter) + wasQuote = !wasQuote; + else + { + if (wasQuote) + { + wasQuote = false; + isQuoted = false; + if (*p == m_cFieldDelimiter) + isFieldStarting = true; + } + } + } + else + { + if (isFieldStarting) + { + isFieldStarting = false; + if (*p == m_cStringDelimiter) + isQuoted = true; + else if (*p == m_cFieldDelimiter) + isFieldStarting = true; + } + else if (*p == m_cFieldDelimiter) + isFieldStarting = true; + } + ++p; + } + + if (wasQuote) + isQuoted = false; + + if (isQuoted) + { + nLastOffset = sLine.Len(); + m_pFileStream->ReadByteStringLine(sLine,nEncoding); + if ( !m_pFileStream->eof() ) + { + OUString aStr = m_aCurrentLine.GetString() + "\n" + sLine.GetString(); + m_aCurrentLine.SetString(aStr); + sLine = m_aCurrentLine; + } + else + break; + } + else + break; + } + } + while(nonEmpty && m_aCurrentLine.Len() == 0); + + if(pEndPos) + *pEndPos = static_cast<sal_Int32>(m_pFileStream->Tell()); + return true; +} + + +void OFlatTable::setRowPos(const vector<TRowPositionInFile>::size_type rowNum, const TRowPositionInFile &rowPos) +{ + assert(m_aRowPosToFilePos.size() >= rowNum); + if(m_aRowPosToFilePos.size() == rowNum) + m_aRowPosToFilePos.push_back(rowPos); + else + { + SAL_WARN_IF(m_aRowPosToFilePos[rowNum] != rowPos, + "connectivity.flat", + "Setting position for row " << rowNum << " to (" << rowPos.first << ", " << rowPos.second << "), " + "but already had different position (" << m_aRowPosToFilePos[rowNum].first << ", " << m_aRowPosToFilePos[rowNum].second << ")"); + m_aRowPosToFilePos[rowNum] = rowPos; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/ETables.cxx b/connectivity/source/drivers/flat/ETables.cxx new file mode 100644 index 000000000..81f366a9e --- /dev/null +++ b/connectivity/source/drivers/flat/ETables.cxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <flat/ETables.hxx> +#include <flat/ETable.hxx> +#include <file/FCatalog.hxx> + +using namespace connectivity; +using namespace ::comphelper; +using namespace connectivity::flat; +using namespace connectivity::file; +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::lang; +using namespace ::com::sun::star::container; + +sdbcx::ObjectType OFlatTables::createObject(const OUString& _rName) +{ + OFlatTable* pRet = new OFlatTable(this, static_cast<OFlatConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection()), + _rName,"TABLE"); + sdbcx::ObjectType xRet = pRet; + pRet->construct(); + return xRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/Eservices.cxx b/connectivity/source/drivers/flat/Eservices.cxx new file mode 100644 index 000000000..e74db8791 --- /dev/null +++ b/connectivity/source/drivers/flat/Eservices.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 <flat/EDriver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::flat; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* flat_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + ODriver::getImplementationName_Static(), + ODriver::getSupportedServiceNames_Static(), + ODriver_CreateInstance, ::cppu::createSingleFactory) + ; + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/flat.component b/connectivity/source/drivers/flat/flat.component new file mode 100644 index 000000000..6fa7fb8e6 --- /dev/null +++ b/connectivity/source/drivers/flat/flat.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="flat" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.flat.ODriver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/hsqldb/HCatalog.cxx b/connectivity/source/drivers/hsqldb/HCatalog.cxx new file mode 100644 index 000000000..029e60f94 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HCatalog.cxx @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HCatalog.hxx> +#include <hsqldb/HUsers.hxx> +#include <hsqldb/HTables.hxx> +#include <hsqldb/HViews.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <comphelper/types.hxx> + + +using namespace connectivity; +using namespace connectivity::hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OHCatalog::OHCatalog(const Reference< XConnection >& _xConnection) : sdbcx::OCatalog(_xConnection) + ,m_xConnection(_xConnection) +{ +} + +void OHCatalog::refreshObjects(const Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames) +{ + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), + "%", + "%", + _sKindOfObject); + fillNames(xResult,_rNames); +} + +void OHCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + + Sequence< OUString > sTableTypes(2); + sTableTypes[0] = "VIEW"; + sTableTypes[1] = "TABLE"; + + refreshObjects(sTableTypes,aVector); + + if ( m_pTables ) + m_pTables->reFill(aVector); + else + m_pTables.reset( new OTables(m_xMetaData,*this,m_aMutex,aVector) ); +} + +void OHCatalog::refreshViews() +{ + Sequence< OUString > aTypes { "VIEW" }; + + bool bSupportsViews = false; + try + { + Reference<XResultSet> xRes = m_xMetaData->getTableTypes(); + Reference<XRow> xRow(xRes,UNO_QUERY); + while ( xRow.is() && xRes->next() ) + { + if ( (bSupportsViews = xRow->getString(1).equalsIgnoreAsciiCase(aTypes[0])) ) + { + break; + } + } + } + catch(const SQLException&) + { + } + + ::std::vector< OUString> aVector; + if ( bSupportsViews ) + refreshObjects(aTypes,aVector); + + if ( m_pViews ) + m_pViews->reFill(aVector); + else + m_pViews.reset( new HViews( m_xConnection, *this, m_aMutex, aVector ) ); +} + +void OHCatalog::refreshGroups() +{ +} + +void OHCatalog::refreshUsers() +{ + ::std::vector< OUString> aVector; + Reference< XStatement > xStmt = m_xConnection->createStatement( ); + Reference< XResultSet > xResult = xStmt->executeQuery("select User from hsqldb.user group by User"); + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while( xResult->next() ) + aVector.push_back(xRow->getString(1)); + ::comphelper::disposeComponent(xResult); + } + ::comphelper::disposeComponent(xStmt); + + if(m_pUsers) + m_pUsers->reFill(aVector); + else + m_pUsers.reset( new OUsers(*this,m_aMutex,aVector,m_xConnection,this) ); +} + +Any SAL_CALL OHCatalog::queryInterface( const Type & rType ) +{ + if ( rType == cppu::UnoType<XGroupsSupplier>::get()) + return Any(); + + return OCatalog::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OHCatalog::getTypes( ) +{ + Sequence< Type > aTypes = OCatalog::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if ( *pBegin != cppu::UnoType<XGroupsSupplier>::get()) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HColumns.cxx b/connectivity/source/drivers/hsqldb/HColumns.cxx new file mode 100644 index 000000000..3f03c3616 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HColumns.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HColumns.hxx> +#include <TConnection.hxx> + + +using namespace ::comphelper; +using namespace connectivity::hsqldb; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OHSQLColumns::OHSQLColumns( ::cppu::OWeakObject& _rParent + ,::osl::Mutex& _rMutex + ,const ::std::vector< OUString> &_rVector + ) : OColumnsHelper(_rParent,true/*_bCase*/,_rMutex,_rVector,true/*_bUseHardRef*/) +{ +} + +Reference< XPropertySet > OHSQLColumns::createDescriptor() +{ + return new OHSQLColumn; +} + + +OHSQLColumn::OHSQLColumn() + : connectivity::sdbcx::OColumn( true/*_bCase*/ ) +{ + construct(); +} + +void OHSQLColumn::construct() +{ + m_sAutoIncrement = "IDENTITY"; + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION),PROPERTY_ID_AUTOINCREMENTCREATION,0,&m_sAutoIncrement, cppu::UnoType<decltype(m_sAutoIncrement)>::get()); +} + +::cppu::IPropertyArrayHelper* OHSQLColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & SAL_CALL OHSQLColumn::getInfoHelper() +{ + return *OHSQLColumn_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +Sequence< OUString > SAL_CALL OHSQLColumn::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbcx.Column" }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HConnection.cxx b/connectivity/source/drivers/hsqldb/HConnection.cxx new file mode 100644 index 000000000..b6cbc1e48 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HConnection.cxx @@ -0,0 +1,340 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <hsqldb/HConnection.hxx> +#include <hsqldb/HTools.hxx> +#include <bitmaps.hlst> + +#include <connectivity/dbtools.hxx> + +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/graphic/GraphicProvider.hpp> +#include <com/sun/star/graphic/XGraphicProvider.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp> + +#include <cppuhelper/exc_hlp.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +#include <resource/sharedresources.hxx> +#include <strings.hrc> + +using ::com::sun::star::util::XFlushListener; +using ::com::sun::star::lang::EventObject; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::XComponentContext; +using ::com::sun::star::sdbc::XStatement; +using ::com::sun::star::sdbc::XConnection; +using ::com::sun::star::sdbcx::XDataDefinitionSupplier; +using ::com::sun::star::sdbcx::XTablesSupplier; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::WrappedTargetException; +using ::com::sun::star::sdbc::XDriver; +using ::com::sun::star::graphic::XGraphic; +using ::com::sun::star::graphic::GraphicProvider; +using ::com::sun::star::graphic::XGraphicProvider; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::sdbc::XResultSet; +using ::com::sun::star::sdbc::XDatabaseMetaData; +using ::com::sun::star::sdbc::XDatabaseMetaData2; +using ::com::sun::star::sdbc::XRow; +using ::com::sun::star::sdb::application::XDatabaseDocumentUI; +using ::com::sun::star::beans::PropertyValue; + + +namespace connectivity::hsqldb +{ + void SAL_CALL OHsqlConnection::disposing() + { + m_aFlushListeners.disposeAndClear( EventObject( *this ) ); + OHsqlConnection_BASE::disposing(); + OConnectionWrapper::disposing(); + } + + OHsqlConnection::OHsqlConnection( const Reference< XDriver >& _rxDriver, + const Reference< XConnection >& _xConnection ,const Reference< XComponentContext >& _rxContext ) + :OHsqlConnection_BASE( m_aMutex ) + ,m_aFlushListeners( m_aMutex ) + ,m_xDriver( _rxDriver ) + ,m_xContext( _rxContext ) + ,m_bIni(true) + ,m_bReadOnly(false) + { + setDelegation(_xConnection,_rxContext,m_refCount); + } + + OHsqlConnection::~OHsqlConnection() + { + if ( !OHsqlConnection_BASE::rBHelper.bDisposed ) + { + osl_atomic_increment( &m_refCount ); + dispose(); + } + } + + IMPLEMENT_FORWARD_XINTERFACE2(OHsqlConnection,OHsqlConnection_BASE,OConnectionWrapper) + IMPLEMENT_SERVICE_INFO(OHsqlConnection, "com.sun.star.sdbc.drivers.hsqldb.OHsqlConnection", "com.sun.star.sdbc.Connection") + IMPLEMENT_FORWARD_XTYPEPROVIDER2(OHsqlConnection,OHsqlConnection_BASE,OConnectionWrapper) + + + ::osl::Mutex& OHsqlConnection::getMutex() const + { + return m_aMutex; + } + + + void OHsqlConnection::checkDisposed() const + { + ::connectivity::checkDisposed( rBHelper.bDisposed ); + } + + // XFlushable + + void SAL_CALL OHsqlConnection::flush( ) + { + MethodGuard aGuard( *this ); + + try + { + if ( m_xConnection.is() ) + { + if ( m_bIni ) + { + m_bIni = false; + Reference< XDatabaseMetaData2 > xMeta2(m_xConnection->getMetaData(),UNO_QUERY_THROW); + const Sequence< PropertyValue > aInfo = xMeta2->getConnectionInfo(); + const PropertyValue* pIter = aInfo.getConstArray(); + const PropertyValue* pEnd = pIter + aInfo.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( pIter->Name == "readonly" ) + m_bReadOnly = true; + } + } + try + { + if ( !m_bReadOnly ) + { + Reference< XStatement > xStmt( m_xConnection->createStatement(), css::uno::UNO_SET_THROW ); + xStmt->execute( "CHECKPOINT DEFRAG" ); + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + } + + EventObject aFlushedEvent( *this ); + m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent ); + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + } + + + void SAL_CALL OHsqlConnection::addFlushListener( const Reference< XFlushListener >& l ) + { + MethodGuard aGuard( *this ); + m_aFlushListeners.addInterface( l ); + } + + + void SAL_CALL OHsqlConnection::removeFlushListener( const Reference< XFlushListener >& l ) + { + MethodGuard aGuard( *this ); + m_aFlushListeners.removeInterface( l ); + } + + + Reference< XGraphic > SAL_CALL OHsqlConnection::getTableIcon( const OUString& TableName, ::sal_Int32 /*_ColorMode*/ ) + { + MethodGuard aGuard( *this ); + + impl_checkExistingTable_throw( TableName ); + if ( !impl_isTextTable_nothrow( TableName ) ) + return nullptr; + + return impl_getTextTableIcon_nothrow(); + } + + + Reference< XInterface > SAL_CALL OHsqlConnection::getTableEditor( const Reference< XDatabaseDocumentUI >& DocumentUI, const OUString& TableName ) + { + MethodGuard aGuard( *this ); + + impl_checkExistingTable_throw( TableName ); + if ( !impl_isTextTable_nothrow( TableName ) ) + return nullptr; + + if ( !DocumentUI.is() ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_NO_DOCUMENTUI)); + throw IllegalArgumentException( + sError, + *this, + 0 + ); + } // if ( !_DocumentUI.is() ) + + +// Reference< XExecutableDialog > xEditor = impl_createLinkedTableEditor_throw( _DocumentUI, _TableName ); +// return xEditor.get(); + return nullptr; + // editor not yet implemented in this CWS + } + + + Reference< XNameAccess > OHsqlConnection::impl_getTableContainer_throw() + { + Reference< XNameAccess > xTables; + try + { + Reference< XConnection > xMe( *this, UNO_QUERY ); + Reference< XDataDefinitionSupplier > xDefinitionsSupp( m_xDriver, UNO_QUERY_THROW ); + Reference< XTablesSupplier > xTablesSupp( xDefinitionsSupp->getDataDefinitionByConnection( xMe ), css::uno::UNO_SET_THROW ); + xTables.set( xTablesSupp->getTables(), css::uno::UNO_SET_THROW ); + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_NO_TABLE_CONTAINER)); + throw WrappedTargetException( sError ,*this, anyEx ); + } + + SAL_WARN_IF( !xTables.is(), "connectivity.hsqldb", "OHsqlConnection::impl_getTableContainer_throw: post condition not met!" ); + return xTables; + } + + //TODO: resource + + void OHsqlConnection::impl_checkExistingTable_throw( const OUString& _rTableName ) + { + bool bDoesExist = false; + try + { + Reference< XNameAccess > xTables( impl_getTableContainer_throw(), css::uno::UNO_SET_THROW ); + bDoesExist = xTables->hasByName( _rTableName ); + } + catch( const Exception& ) + { + // that's a serious error in impl_getTableContainer_throw, or hasByName, however, we're only + // allowed to throw an IllegalArgumentException ourself + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + + if ( !bDoesExist ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_NO_TABLENAME, + "$tablename$", _rTableName + )); + throw IllegalArgumentException( sError,*this, 0 ); + } // if ( !bDoesExist ) + } + + + bool OHsqlConnection::impl_isTextTable_nothrow( const OUString& _rTableName ) + { + bool bIsTextTable = false; + try + { + Reference< XConnection > xMe( *this, UNO_QUERY_THROW ); + + // split the fully qualified name + Reference< XDatabaseMetaData > xMetaData( xMe->getMetaData(), css::uno::UNO_SET_THROW ); + OUString sCatalog, sSchema, sName; + ::dbtools::qualifiedNameComponents( xMetaData, _rTableName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::Complete ); + + // get the table information + OUStringBuffer sSQL; + sSQL.append( "SELECT HSQLDB_TYPE FROM INFORMATION_SCHEMA.SYSTEM_TABLES" ); + HTools::appendTableFilterCrit( sSQL, sCatalog, sSchema, sName, true ); + sSQL.append( " AND TABLE_TYPE = 'TABLE'" ); + + Reference< XStatement > xStatement( xMe->createStatement(), css::uno::UNO_SET_THROW ); + Reference< XResultSet > xTableHsqlType( xStatement->executeQuery( sSQL.makeStringAndClear() ), css::uno::UNO_SET_THROW ); + + if ( xTableHsqlType->next() ) // might not succeed in case of VIEWs + { + Reference< XRow > xValueAccess( xTableHsqlType, UNO_QUERY_THROW ); + OUString sTableType = xValueAccess->getString( 1 ); + bIsTextTable = sTableType == "TEXT"; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + + return bIsTextTable; + } + + + Reference< XGraphic > OHsqlConnection::impl_getTextTableIcon_nothrow() + { + Reference< XGraphic > xGraphic; + try + { + // create a graphic provider + Reference< XGraphicProvider > xProvider; + if ( m_xContext.is() ) + xProvider.set( GraphicProvider::create(m_xContext) ); + + // assemble the image URL + OUString sImageURL = + // load the graphic from the global graphic repository + "private:graphicrepository/" + // the relative path within the images.zip + LINKED_TEXT_TABLE_IMAGE_RESOURCE; + + // ask the provider to obtain a graphic + Sequence< PropertyValue > aMediaProperties( 1 ); + aMediaProperties[0].Name = "URL"; + aMediaProperties[0].Value <<= sImageURL; + xGraphic = xProvider->queryGraphic( aMediaProperties ); + OSL_ENSURE( xGraphic.is(), "OHsqlConnection::impl_getTextTableIcon_nothrow: the provider did not give us a graphic object!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + return xGraphic; + } + +} // namespace connectivity::hsqldb + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HDriver.cxx b/connectivity/source/drivers/hsqldb/HDriver.cxx new file mode 100644 index 000000000..05b9478a9 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HDriver.cxx @@ -0,0 +1,870 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HDriver.hxx> +#include <hsqldb/HConnection.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/sdbc/DriverManager.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <TConnection.hxx> +#include <hsqldb/HStorageMap.hxx> +#include <jvmfwk/framework.hxx> +#include <com/sun/star/reflection/XProxyFactory.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/util/XFlushable.hpp> +#include "HTerminateListener.hxx" +#include <hsqldb/HCatalog.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/file.h> +#include <osl/process.h> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/types.hxx> +#include <unotools/confignode.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <tools/diagnose_ex.h> + +#include <memory> + + +namespace connectivity +{ + + using namespace hsqldb; + using namespace css::uno; + using namespace css::sdbc; + using namespace css::sdbcx; + using namespace css::beans; + using namespace css::frame; + using namespace css::lang; + using namespace css::embed; + using namespace css::io; + using namespace css::util; + using namespace css::reflection; + + namespace hsqldb + { + Reference< XInterface > ODriverDelegator_CreateInstance(const Reference< css::lang::XMultiServiceFactory >& _rxFac) + { + return *(new ODriverDelegator(comphelper::getComponentContext(_rxFac))); + } + } + + + ODriverDelegator::ODriverDelegator(const Reference< XComponentContext >& _rxContext) + : ODriverDelegator_BASE(m_aMutex) + ,m_xContext(_rxContext) + ,m_bInShutDownConnections(false) + { + } + + + ODriverDelegator::~ODriverDelegator() + { + try + { + ::comphelper::disposeComponent(m_xDriver); + } + catch(const Exception&) + { + } + } + + + void SAL_CALL ODriverDelegator::disposing() + { + ::osl::MutexGuard aGuard(m_aMutex); + + try + { + for (const auto& rConnection : m_aConnections) + { + Reference<XInterface > xTemp = rConnection.first.get(); + ::comphelper::disposeComponent(xTemp); + } + } + catch(Exception&) + { + // not interested in + } + m_aConnections.clear(); + TWeakPairVector().swap(m_aConnections); + + cppu::WeakComponentImplHelperBase::disposing(); + } + + Reference< XDriver > const & ODriverDelegator::loadDriver( ) + { + if ( !m_xDriver.is() ) + { + Reference<XDriverManager2> xDriverAccess = DriverManager::create( m_xContext ); + m_xDriver = xDriverAccess->getDriverByURL("jdbc:hsqldb:db"); + } + + return m_xDriver; + } + + + namespace + { + OUString lcl_getPermittedJavaMethods_nothrow( const Reference< XComponentContext >& _rxContext ) + { + OUString aConfigPath = + "/org.openoffice.Office.DataAccess/DriverSettings/" + + ODriverDelegator::getImplementationName_Static() + + "/PermittedJavaMethods"; + ::utl::OConfigurationTreeRoot aConfig( ::utl::OConfigurationTreeRoot::createWithComponentContext( + _rxContext, aConfigPath ) ); + + OUStringBuffer aPermittedMethods; + const Sequence< OUString > aNodeNames( aConfig.getNodeNames() ); + for ( auto const & nodeName : aNodeNames ) + { + OUString sPermittedMethod; + OSL_VERIFY( aConfig.getNodeValue( nodeName ) >>= sPermittedMethod ); + + if ( !aPermittedMethods.isEmpty() ) + aPermittedMethods.append( ';' ); + aPermittedMethods.append( sPermittedMethod ); + } + + return aPermittedMethods.makeStringAndClear(); + } + } + + + Reference< XConnection > SAL_CALL ODriverDelegator::connect( const OUString& url, const Sequence< PropertyValue >& info ) + { + Reference< XConnection > xConnection; + if ( acceptsURL(url) ) + { + Reference< XDriver > xDriver = loadDriver(); + if ( xDriver.is() ) + { + OUString sURL; + Reference<XStorage> xStorage; + const PropertyValue* pIter = info.getConstArray(); + const PropertyValue* pEnd = pIter + info.getLength(); + + for (;pIter != pEnd; ++pIter) + { + if ( pIter->Name == "Storage" ) + { + xStorage.set(pIter->Value,UNO_QUERY); + } + else if ( pIter->Name == "URL" ) + { + pIter->Value >>= sURL; + } + } + + if ( !xStorage.is() || sURL.isEmpty() ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_NO_STORAGE); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + OUString sSystemPath; + osl_getSystemPathFromFileURL( sURL.pData, &sSystemPath.pData ); + if ( sURL.isEmpty() || sSystemPath.isEmpty() ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_INVALID_FILE_URL); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + bool bIsNewDatabase = !xStorage->hasElements(); + + ::comphelper::NamedValueCollection aProperties; + + // properties for accessing the embedded storage + OUString sKey = StorageContainer::registerStorage( xStorage, sSystemPath ); + aProperties.put( "storage_key", sKey ); + aProperties.put( "storage_class_name", + OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageAccess" ) ); + aProperties.put( "fileaccess_class_name", + OUString( "com.sun.star.sdbcx.comp.hsqldb.StorageFileAccess" ) ); + + // JDBC driver and driver's classpath + aProperties.put( "JavaDriverClass", + OUString( "org.hsqldb.jdbcDriver" ) ); + aProperties.put( "JavaDriverClassPath", + OUString( +#ifdef SYSTEM_HSQLDB + HSQLDB_JAR +#else + "vnd.sun.star.expand:$LO_JAVA_DIR/hsqldb.jar" +#endif + " vnd.sun.star.expand:$LO_JAVA_DIR/sdbc_hsqldb.jar" + ) ); + + // auto increment handling + aProperties.put( "IsAutoRetrievingEnabled", true ); + aProperties.put( "AutoRetrievingStatement", + OUString( "CALL IDENTITY()" ) ); + aProperties.put( "IgnoreDriverPrivileges", true ); + + // don't want to expose HSQLDB's schema capabilities which exist since 1.8.0RC10 + aProperties.put( "default_schema", + OUString( "true" ) ); + + // security: permitted Java classes + NamedValue aPermittedClasses( + "hsqldb.method_class_names", + makeAny( lcl_getPermittedJavaMethods_nothrow( m_xContext ) ) + ); + aProperties.put( "SystemProperties", Sequence< NamedValue >( &aPermittedClasses, 1 ) ); + + const OUString sProperties( "properties" ); + OUString sMessage; + try + { + if ( !bIsNewDatabase && xStorage->isStreamElement(sProperties) ) + { + Reference<XStream > xStream = xStorage->openStreamElement(sProperties,ElementModes::READ); + if ( xStream.is() ) + { + std::unique_ptr<SvStream> pStream( ::utl::UcbStreamHelper::CreateStream(xStream) ); + if (pStream) + { + OString sLine; + OString sVersionString; + while ( pStream->ReadLine(sLine) ) + { + if ( sLine.isEmpty() ) + continue; + sal_Int32 nIdx {0}; + const OString sIniKey = sLine.getToken(0, '=', nIdx); + const OString sValue = sLine.getToken(0, '=', nIdx); + if( sIniKey == "hsqldb.compatible_version" ) + { + sVersionString = sValue; + } + else + { + if (sIniKey == "version" && sVersionString.isEmpty()) + { + sVersionString = sValue; + } + } + } + if (!sVersionString.isEmpty()) + { + sal_Int32 nIdx {0}; + const sal_Int32 nMajor = sVersionString.getToken(0, '.', nIdx).toInt32(); + const sal_Int32 nMinor = sVersionString.getToken(0, '.', nIdx).toInt32(); + const sal_Int32 nMicro = sVersionString.getToken(0, '.', nIdx).toInt32(); + if ( nMajor > 1 + || ( nMajor == 1 && nMinor > 8 ) + || ( nMajor == 1 && nMinor == 8 && nMicro > 0 ) ) + { + ::connectivity::SharedResources aResources; + sMessage = aResources.getResourceString(STR_ERROR_NEW_VERSION); + } + } + } + } // if ( xStream.is() ) + ::comphelper::disposeComponent(xStream); + } + } + catch(Exception&) + { + } + if ( !sMessage.isEmpty() ) + { + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + // readonly? + Reference<XPropertySet> xProp(xStorage,UNO_QUERY); + if ( xProp.is() ) + { + sal_Int32 nMode = 0; + xProp->getPropertyValue("OpenMode") >>= nMode; + if ( (nMode & ElementModes::WRITE) != ElementModes::WRITE ) + { + aProperties.put( "readonly", OUString( "true" ) ); + } + } + + Sequence< PropertyValue > aConnectionArgs; + aProperties >>= aConnectionArgs; + OUString sConnectURL = "jdbc:hsqldb:" + sSystemPath; + Reference<XConnection> xOrig; + try + { + xOrig = xDriver->connect( sConnectURL, aConnectionArgs ); + } + catch(const Exception&) + { + StorageContainer::revokeStorage(sKey,nullptr); + throw; + } + + // if the storage is completely empty, then we just created a new HSQLDB + // In this case, do some initializations. + if ( bIsNewDatabase && xOrig.is() ) + onConnectedNewDatabase( xOrig ); + + if ( xOrig.is() ) + { + // now we have to set the URL to get the correct answer for metadata()->getURL() + auto pMetaConnection = comphelper::getUnoTunnelImplementation<OMetaConnection>(xOrig); + if ( pMetaConnection ) + pMetaConnection->setURL(url); + + Reference<XComponent> xComp(xOrig,UNO_QUERY); + if ( xComp.is() ) + xComp->addEventListener(this); + + // we want to close all connections when the office shuts down + static Reference< XTerminateListener> s_xTerminateListener = [&]() + { + Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext ); + + auto tmp = new OConnectionController(this); + xDesktop->addTerminateListener(tmp); + return tmp; + }(); + Reference< XComponent> xIfc = new OHsqlConnection( this, xOrig, m_xContext ); + xConnection.set(xIfc,UNO_QUERY); + m_aConnections.push_back(TWeakPair(WeakReferenceHelper(xOrig),TWeakConnectionPair(sKey,TWeakRefPair(WeakReferenceHelper(xConnection),WeakReferenceHelper())))); + + Reference<XTransactionBroadcaster> xBroad(xStorage,UNO_QUERY); + if ( xBroad.is() ) + { + Reference<XTransactionListener> xListener(*this,UNO_QUERY); + xBroad->addTransactionListener(xListener); + } + } + } + } + return xConnection; + } + + + sal_Bool SAL_CALL ODriverDelegator::acceptsURL( const OUString& url ) + { + bool bEnabled = false; + javaFrameworkError e = jfw_getEnabled(&bEnabled); + switch (e) { + case JFW_E_NONE: + break; + case JFW_E_DIRECT_MODE: + SAL_INFO( + "connectivity.hsqldb", + "jfw_getEnabled: JFW_E_DIRECT_MODE, assuming true"); + bEnabled = true; + break; + default: + SAL_WARN( + "connectivity.hsqldb", "jfw_getEnabled: error code " << +e); + break; + } + return bEnabled && url == "sdbc:embedded:hsqldb"; + } + + + Sequence< DriverPropertyInfo > SAL_CALL ODriverDelegator::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) + { + if ( !acceptsURL(url) ) + return Sequence< DriverPropertyInfo >(); + std::vector< DriverPropertyInfo > aDriverInfo; + aDriverInfo.push_back(DriverPropertyInfo( + "Storage" + ,"Defines the storage where the database will be stored." + ,true + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "URL" + ,"Defines the url of the data source." + ,true + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "AutoRetrievingStatement" + ,"Defines the statement which will be executed to retrieve auto increment values." + ,false + ,"CALL IDENTITY()" + ,Sequence< OUString >()) + ); + return Sequence< DriverPropertyInfo >(aDriverInfo.data(),aDriverInfo.size()); + } + + + sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion( ) + { + return 1; + } + + + sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion( ) + { + return 0; + } + + + Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByConnection( const Reference< XConnection >& connection ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed); + + Reference< XTablesSupplier > xTab; + + TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(), + [&connection](const TWeakPairVector::value_type& rConnection) { + return rConnection.second.second.first.get() == connection.get(); }); + if (i != m_aConnections.end()) + { + xTab.set(i->second.second.second,UNO_QUERY); + if ( !xTab.is() ) + { + xTab = new OHCatalog(connection); + i->second.second.second = WeakReferenceHelper(xTab); + } + } + + return xTab; + } + + + Reference< XTablesSupplier > SAL_CALL ODriverDelegator::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info ) + { + if ( ! acceptsURL(url) ) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + } + + return getDataDefinitionByConnection(connect(url,info)); + } + + // XServiceInfo + + + OUString ODriverDelegator::getImplementationName_Static( ) + { + return "com.sun.star.sdbcx.comp.hsqldb.Driver"; + } + + Sequence< OUString > ODriverDelegator::getSupportedServiceNames_Static( ) + { + return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" }; + } + + OUString SAL_CALL ODriverDelegator::getImplementationName( ) + { + return getImplementationName_Static(); + } + + sal_Bool SAL_CALL ODriverDelegator::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL ODriverDelegator::getSupportedServiceNames( ) + { + return getSupportedServiceNames_Static(); + } + + void SAL_CALL ODriverDelegator::createCatalog( const Sequence< PropertyValue >& /*info*/ ) + { + ::dbtools::throwFeatureNotImplementedSQLException( "XCreateCatalog::createCatalog", *this ); + } + + void ODriverDelegator::shutdownConnection(const TWeakPairVector::iterator& _aIter ) + { + OSL_ENSURE(m_aConnections.end() != _aIter,"Iterator equals .end()"); + bool bLastOne = true; + try + { + Reference<XConnection> _xConnection(_aIter->first.get(),UNO_QUERY); + + if ( _xConnection.is() ) + { + Reference<XStatement> xStmt = _xConnection->createStatement(); + if ( xStmt.is() ) + { + Reference<XResultSet> xRes = xStmt->executeQuery("SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_SESSIONS WHERE USER_NAME ='SA'"); + Reference<XRow> xRow(xRes,UNO_QUERY); + if ( xRow.is() && xRes->next() ) + bLastOne = xRow->getInt(1) == 1; + if ( bLastOne ) + xStmt->execute("SHUTDOWN"); + } + } + } + catch(Exception&) + { + } + if ( bLastOne ) + { + // Reference<XTransactionListener> xListener(*this,UNO_QUERY); + // a shutdown should commit all changes to the db files + StorageContainer::revokeStorage(_aIter->second.first,nullptr); + } + if ( !m_bInShutDownConnections ) + m_aConnections.erase(_aIter); + } + + void SAL_CALL ODriverDelegator::disposing( const css::lang::EventObject& Source ) + { + ::osl::MutexGuard aGuard(m_aMutex); + Reference<XConnection> xCon(Source.Source,UNO_QUERY); + if ( xCon.is() ) + { + TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(), + [&xCon](const TWeakPairVector::value_type& rConnection) { return rConnection.first.get() == xCon.get(); }); + + if (i != m_aConnections.end()) + shutdownConnection(i); + } + else + { + Reference< XStorage> xStorage(Source.Source,UNO_QUERY); + if ( xStorage.is() ) + { + OUString sKey = StorageContainer::getRegisteredKey(xStorage); + TWeakPairVector::iterator i = std::find_if(m_aConnections.begin(),m_aConnections.end(), + [&sKey] (const TWeakPairVector::value_type& conn) { + return conn.second.first == sKey; + }); + + if ( i != m_aConnections.end() ) + shutdownConnection(i); + } + } + } + + void ODriverDelegator::shutdownConnections() + { + m_bInShutDownConnections = true; + for (const auto& rConnection : m_aConnections) + { + try + { + Reference<XConnection> xCon(rConnection.first,UNO_QUERY); + ::comphelper::disposeComponent(xCon); + } + catch(Exception&) + { + } + } + m_aConnections.clear(); + m_bInShutDownConnections = true; + } + + void ODriverDelegator::flushConnections() + { + for (const auto& rConnection : m_aConnections) + { + try + { + Reference<XFlushable> xCon(rConnection.second.second.first.get(),UNO_QUERY); + if (xCon.is()) + xCon->flush(); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + } + } + + void SAL_CALL ODriverDelegator::preCommit( const css::lang::EventObject& aEvent ) + { + ::osl::MutexGuard aGuard(m_aMutex); + + Reference< XStorage> xStorage(aEvent.Source,UNO_QUERY); + OUString sKey = StorageContainer::getRegisteredKey(xStorage); + if ( sKey.isEmpty() ) + return; + + TWeakPairVector::const_iterator i = std::find_if(m_aConnections.begin(), m_aConnections.end(), + [&sKey] (const TWeakPairVector::value_type& conn) { + return conn.second.first == sKey; + }); + + OSL_ENSURE( i != m_aConnections.end(), "ODriverDelegator::preCommit: they're committing a storage which I do not know!" ); + if ( i == m_aConnections.end() ) + return; + + try + { + Reference<XConnection> xConnection(i->first,UNO_QUERY); + if ( xConnection.is() ) + { + Reference< XStatement> xStmt = xConnection->createStatement(); + OSL_ENSURE( xStmt.is(), "ODriverDelegator::preCommit: no statement!" ); + if ( xStmt.is() ) + xStmt->execute( "SET WRITE_DELAY 0" ); + + bool bPreviousAutoCommit = xConnection->getAutoCommit(); + xConnection->setAutoCommit( false ); + xConnection->commit(); + xConnection->setAutoCommit( bPreviousAutoCommit ); + + if ( xStmt.is() ) + xStmt->execute( "SET WRITE_DELAY 60" ); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::preCommit" ); + } + } + + void SAL_CALL ODriverDelegator::commited( const css::lang::EventObject& /*aEvent*/ ) + { + } + + void SAL_CALL ODriverDelegator::preRevert( const css::lang::EventObject& /*aEvent*/ ) + { + } + + void SAL_CALL ODriverDelegator::reverted( const css::lang::EventObject& /*aEvent*/ ) + { + } + + namespace + { + + const char* lcl_getCollationForLocale( const OUString& _rLocaleString, bool _bAcceptCountryMismatch = false ) + { + static const char* pTranslations[] = + { + "af-ZA", "Afrikaans", + "am-ET", "Amharic", + "ar", "Arabic", + "as-IN", "Assamese", + "az-AZ", "Azerbaijani_Latin", + "az-cyrillic", "Azerbaijani_Cyrillic", + "be-BY", "Belarusian", + "bg-BG", "Bulgarian", + "bn-IN", "Bengali", + "bo-CN", "Tibetan", + "bs-BA", "Bosnian", + "ca-ES", "Catalan", + "cs-CZ", "Czech", + "cy-GB", "Welsh", + "da-DK", "Danish", + "de-DE", "German", + "el-GR", "Greek", + "en-US", "Latin1_General", + "es-ES", "Spanish", + "et-EE", "Estonian", + "eu", "Basque", + "fi-FI", "Finnish", + "fr-FR", "French", + "gn-PY", "Guarani", + "gu-IN", "Gujarati", + "ha-NG", "Hausa", + "he-IL", "Hebrew", + "hi-IN", "Hindi", + "hr-HR", "Croatian", + "hu-HU", "Hungarian", + "hy-AM", "Armenian", + "id-ID", "Indonesian", + "ig-NG", "Igbo", + "is-IS", "Icelandic", + "it-IT", "Italian", + "iu-CA", "Inuktitut", + "ja-JP", "Japanese", + "ka-GE", "Georgian", + "kk-KZ", "Kazakh", + "km-KH", "Khmer", + "kn-IN", "Kannada", + "ko-KR", "Korean", + "kok-IN", "Konkani", + "ks", "Kashmiri", + "ky-KG", "Kirghiz", + "lo-LA", "Lao", + "lt-LT", "Lithuanian", + "lv-LV", "Latvian", + "mi-NZ", "Maori", + "mk-MK", "Macedonian", + "ml-IN", "Malayalam", + "mn-MN", "Mongolian", + "mni-IN", "Manipuri", + "mr-IN", "Marathi", + "ms-MY", "Malay", + "mt-MT", "Maltese", + "my-MM", "Burmese", + "nb-NO", "Danish_Norwegian", + "ne-NP", "Nepali", + "nl-NL", "Dutch", + "nn-NO", "Norwegian", + "or-IN", "Odia", + "pa-IN", "Punjabi", + "pl-PL", "Polish", + "ps-AF", "Pashto", + "pt-PT", "Portuguese", + "ro-RO", "Romanian", + "ru-RU", "Russian", + "sa-IN", "Sanskrit", + "sd-IN", "Sindhi", + "sk-SK", "Slovak", + "sl-SI", "Slovenian", + "so-SO", "Somali", + "sq-AL", "Albanian", + "sr-YU", "Serbian_Cyrillic", + "sv-SE", "Swedish", + "sw-KE", "Swahili", + "ta-IN", "Tamil", + "te-IN", "Telugu", + "tg-TJ", "Tajik", + "th-TH", "Thai", + "tk-TM", "Turkmen", + "tn-BW", "Tswana", + "tr-TR", "Turkish", + "tt-RU", "Tatar", + "uk-UA", "Ukrainian", + "ur-PK", "Urdu", + "uz-UZ", "Uzbek_Latin", + "ven-ZA", "Venda", + "vi-VN", "Vietnamese", + "yo-NG", "Yoruba", + "zh-CN", "Chinese", + "zu-ZA", "Zulu", + nullptr, nullptr + }; + + OUString sLocaleString( _rLocaleString ); + char nCompareTermination = 0; + + if ( _bAcceptCountryMismatch ) + { + // strip the country part from the compare string + sal_Int32 nCountrySep = sLocaleString.indexOf( '-' ); + if ( nCountrySep > -1 ) + sLocaleString = sLocaleString.copy( 0, nCountrySep ); + + // the entries in the translation table are compared until the + // - character only, not until the terminating 0 + nCompareTermination = '-'; + } + + const char** pLookup = pTranslations; + for ( ; *pLookup; pLookup +=2 ) + { + sal_Int32 nCompareUntil = 0; + while ( (*pLookup)[ nCompareUntil ] != nCompareTermination && (*pLookup)[ nCompareUntil ] != 0 ) + ++nCompareUntil; + + if ( sLocaleString.equalsAsciiL( *pLookup, nCompareUntil ) ) + return *( pLookup + 1 ); + } + + if ( !_bAcceptCountryMismatch ) + // second round, this time without matching the country + return lcl_getCollationForLocale( _rLocaleString, true ); + + OSL_FAIL( "lcl_getCollationForLocale: unknown locale string, falling back to Latin1_General!" ); + return "Latin1_General"; + } + + + OUString lcl_getSystemLocale( const Reference< XComponentContext >& _rxContext ) + { + OUString sLocaleString = "en-US"; + try + { + + Reference< XMultiServiceFactory > xConfigProvider( + css::configuration::theDefaultProvider::get( _rxContext ) ); + + + // arguments for creating the config access + Sequence<Any> aArguments(comphelper::InitAnyPropertySequence( + { + {"nodepath", Any(OUString("/org.openoffice.Setup/L10N" ))}, // the path to the node to open + {"depth", Any(sal_Int32(-1))}, // the depth: -1 means unlimited + })); + // create the access + Reference< XPropertySet > xNode( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + aArguments ), + UNO_QUERY ); + OSL_ENSURE( xNode.is(), "lcl_getSystemLocale: invalid access returned (should throw an exception instead)!" ); + + + // ask for the system locale setting + if ( xNode.is() ) + xNode->getPropertyValue("ooSetupSystemLocale") >>= sLocaleString; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "lcl_getSystemLocale" ); + } + if ( sLocaleString.isEmpty() ) + { + rtl_Locale* pProcessLocale = nullptr; + osl_getProcessLocale( &pProcessLocale ); + sLocaleString = LanguageTag( *pProcessLocale).getBcp47(); + } + return sLocaleString; + } + } + + void ODriverDelegator::onConnectedNewDatabase( const Reference< XConnection >& _rxConnection ) + { + try + { + Reference< XStatement > xStatement = _rxConnection->createStatement(); + OSL_ENSURE( xStatement.is(), "ODriverDelegator::onConnectedNewDatabase: could not create a statement!" ); + if ( xStatement.is() ) + { + OUStringBuffer aStatement; + aStatement.append( "SET DATABASE COLLATION \"" ); + aStatement.appendAscii( lcl_getCollationForLocale( lcl_getSystemLocale( m_xContext ) ) ); + aStatement.append( "\"" ); + + xStatement->execute( aStatement.makeStringAndClear() ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.hsqldb", "ODriverDelegator::onConnectedNewDatabase" ); + } + } + + +} // namespace connectivity + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HStorageAccess.cxx b/connectivity/source/drivers/hsqldb/HStorageAccess.cxx new file mode 100644 index 000000000..60e3fd0ee --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HStorageAccess.cxx @@ -0,0 +1,508 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HStorageAccess.hxx> +#include <com/sun/star/embed/XStorage.hpp> +#include <hsqldb/HStorageMap.hxx> +#include "accesslog.hxx" +#include <osl/diagnose.h> + +#include <string.h> + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::connectivity::hsqldb; + +#define ThrowException(env, type, msg) { \ + env->ThrowNew(env->FindClass(type), msg); } + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: openStream + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_openStream + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key, jint mode) +{ +#ifdef HSQLDB_DBG + { + OperationLogFile( env, name, "data" ).logOperation( "openStream" ); + LogFile( env, name, "data" ).create(); + } +#endif + + StorageContainer::registerStream(env,name,key,mode); +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: close + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_close + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + { + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sName = StorageContainer::jstring2ustring(env,name); + } +#endif + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XOutputStream> xFlush = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>(); + if ( xFlush.is() ) + try + { + xFlush->flush(); + } + catch(const Exception&) + { + OSL_FAIL( "NativeStorageAccess::close: caught an exception while flushing!" ); + } +#ifdef HSQLDB_DBG + { + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "close" ); + aOpLog.close(); + + LogFile aDataLog( env, name, "data" ); + aDataLog.close(); + } +#endif + + StorageContainer::revokeStream(env,name,key); +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: getFilePointer + * Signature: (Ljava/lang/String;Ljava/lang/String;)J + */ +extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_getFilePointer + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "getFilePointer" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper.get(),"No stream helper!"); + + jlong nReturn = pHelper ? pHelper->getSeek()->getPosition() : jlong(0); +#ifdef HSQLDB_DBG + aOpLog.logReturn( nReturn ); +#endif + return nReturn; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: length + * Signature: (Ljava/lang/String;Ljava/lang/String;)J + */ +extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_length + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "length" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper.get(),"No stream helper!"); + + jlong nReturn = pHelper ? pHelper->getSeek()->getLength() :jlong(0); +#ifdef HSQLDB_DBG + aOpLog.logReturn( nReturn ); +#endif + return nReturn; +} + + +jint read_from_storage_stream( JNIEnv * env, jstring name, jstring key ) +{ + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>(); + OSL_ENSURE(xIn.is(),"Input stream is NULL!"); + if ( xIn.is() ) + { + Sequence< ::sal_Int8 > aData(1); + sal_Int32 nBytesRead = -1; + try + { + nBytesRead = xIn->readBytes(aData,1); + } + catch(const Exception& e) + { + StorageContainer::throwJavaException(e,env); + return -1; + + } + if (nBytesRead <= 0) + { + return -1; + } + else + { + return static_cast<unsigned char>(aData[0]); + } + } + return -1; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_read__Ljava_lang_String_2Ljava_lang_String_2 + (JNIEnv* env, jobject /*obj_this*/, jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "read" ); + + DataLogFile aDataLog( env, name, "data" ); + return read_from_storage_stream( env, obj_this, name, key, &aDataLog ); +#else + return read_from_storage_stream( env, name, key ); +#endif +} + + +jint read_from_storage_stream_into_buffer( JNIEnv * env, jstring name, jstring key, jbyteArray buffer, jint off, jint len ) +{ +#ifdef HSQLDB_DBG + { + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sName = StorageContainer::jstring2ustring(env,name); + } +#endif + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>(); + OSL_ENSURE(xIn.is(),"Input stream is NULL!"); + if ( xIn.is() ) + { + jsize nLen = env->GetArrayLength(buffer); + if ( nLen < len || len <= 0 ) + { + ThrowException( env, + "java/io/IOException", + "len is greater or equal to the buffer size"); + return -1; + } + sal_Int32 nBytesRead = -1; + + Sequence< ::sal_Int8 > aData(nLen); + try + { + nBytesRead = xIn->readBytes(aData, len); + } + catch(const Exception& e) + { + StorageContainer::throwJavaException(e,env); + return -1; + } + + if (nBytesRead <= 0) + return -1; + env->SetByteArrayRegion(buffer,off,nBytesRead,reinterpret_cast<jbyte*>(&aData[0])); + + return nBytesRead; + } + ThrowException( env, + "java/io/IOException", + "Stream is not valid"); + return -1; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_read__Ljava_lang_String_2Ljava_lang_String_2_3BII + (JNIEnv * env, jobject obj_this,jstring name, jstring key, jbyteArray buffer, jint off, jint len) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "read( byte[], int, int )" ); + + DataLogFile aDataLog( env, name, "data" ); + return read_from_storage_stream_into_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog ); +#else + (void)obj_this; + return read_from_storage_stream_into_buffer( env, name, key, buffer, off, len ); +#endif +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: readInt + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_readInt + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "readInt" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>(); + OSL_ENSURE(xIn.is(),"Input stream is NULL!"); + if ( xIn.is() ) + { + Sequence< ::sal_Int8 > aData(4); + sal_Int32 nBytesRead = -1; + try + { + nBytesRead = xIn->readBytes(aData, 4); + } + catch(const Exception& e) + { + StorageContainer::throwJavaException(e,env); + return -1; + } + + if ( nBytesRead != 4 ) { + ThrowException( env, + "java/io/IOException", + "Bytes read != 4"); + return -1; + } + + Sequence< sal_Int32 > ch(4); + for(sal_Int32 i = 0;i < 4; ++i) + { + ch[i] = static_cast<unsigned char>(aData[i]); + } + + if ((ch[0] | ch[1] | ch[2] | ch[3]) < 0) + { + ThrowException( env, + "java/io/IOException", + "One byte is < 0"); + return -1; + } + jint nRet = (ch[0] << 24) + (ch[1] << 16) + (ch[2] << 8) + (ch[3] << 0); +#ifdef HSQLDB_DBG + DataLogFile aDataLog( env, name, "data" ); + aDataLog.write( nRet ); + + aOpLog.logReturn( nRet ); +#endif + return nRet; + } + ThrowException( env, + "java/io/IOException", + "No InputStream"); + return -1; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: seek + * Signature: (Ljava/lang/String;Ljava/lang/String;J)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_seek + (JNIEnv * env, jobject /*obj_this*/,jstring name, jstring key, jlong position) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "seek", position ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XSeekable> xSeek = pHelper ? pHelper->getSeek() : Reference< XSeekable>(); + + OSL_ENSURE(xSeek.is(),"No Seekable stream!"); + if ( !xSeek.is() ) + return; + +#ifdef HSQLDB_DBG + DataLogFile aDataLog( env, name, "data" ); +#endif + + ::sal_Int64 nLen = xSeek->getLength(); + if ( nLen < position) + { + static const ::sal_Int64 BUFFER_SIZE = 9192; + #ifdef HSQLDB_DBG + aDataLog.seek( nLen ); + #endif + xSeek->seek(nLen); + Reference< XOutputStream> xOut = pHelper->getOutputStream(); + OSL_ENSURE(xOut.is(),"No output stream!"); + + ::sal_Int64 diff = position - nLen; + sal_Int32 n; + while( diff != 0 ) + { + if ( BUFFER_SIZE < diff ) + { + n = static_cast<sal_Int32>(BUFFER_SIZE); + diff = diff - BUFFER_SIZE; + } + else + { + n = static_cast<sal_Int32>(diff); + diff = 0; + } + Sequence< ::sal_Int8 > aData(n); + memset(aData.getArray(),0,n); + xOut->writeBytes(aData); + #ifdef HSQLDB_DBG + aDataLog.write( aData.getConstArray(), n ); + #endif + } + } + xSeek->seek(position); + OSL_ENSURE(xSeek->getPosition() == position,"Wrong position after seeking the stream"); + +#ifdef HSQLDB_DBG + aDataLog.seek( position ); + OSL_ENSURE( xSeek->getPosition() == aDataLog.tell(), "Wrong position after seeking the stream" ); +#endif +} + + +void write_to_storage_stream_from_buffer( JNIEnv* env, jstring name, jstring key, jbyteArray buffer, jint off, jint len ) +{ + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XOutputStream> xOut = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>(); + OSL_ENSURE(xOut.is(),"Stream is NULL"); + + try + { + if ( xOut.is() ) + { + jbyte *buf = env->GetByteArrayElements(buffer,nullptr); + if (env->ExceptionCheck()) + { + env->ExceptionClear(); + OSL_FAIL("ExceptionClear"); + } + OSL_ENSURE(buf,"buf is NULL"); + if ( buf && len > 0 && len <= env->GetArrayLength(buffer)) + { + Sequence< ::sal_Int8 > aData(reinterpret_cast<sal_Int8 *>(buf + off),len); + env->ReleaseByteArrayElements(buffer, buf, JNI_ABORT); + xOut->writeBytes(aData); + } + } + else + { + ThrowException( env, + "java/io/IOException", + "No OutputStream"); + } + } + catch(const Exception& e) + { + OSL_FAIL("Exception caught! : write [BII)V"); + StorageContainer::throwJavaException(e,env); + } +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: write + * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_write + (JNIEnv * env, jobject obj_this,jstring name, jstring key, jbyteArray buffer, jint off, jint len) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "write( byte[], int, int )" ); + + DataLogFile aDataLog( env, name, "data" ); + write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream_from_buffer( env, name, key, buffer, off, len ); +#endif +} + + +void write_to_storage_stream( JNIEnv* env, jstring name, jstring key, jint v ) +{ + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XOutputStream> xOut = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>(); + OSL_ENSURE(xOut.is(),"Stream is NULL"); + try + { + if ( xOut.is() ) + { + Sequence< ::sal_Int8 > oneByte(4); + oneByte[0] = static_cast<sal_Int8>((v >> 24) & 0xFF); + oneByte[1] = static_cast<sal_Int8>((v >> 16) & 0xFF); + oneByte[2] = static_cast<sal_Int8>((v >> 8) & 0xFF); + oneByte[3] = static_cast<sal_Int8>((v >> 0) & 0xFF); + + xOut->writeBytes(oneByte); + } + else + { + ThrowException( env, + "java/io/IOException", + "No OutputStream"); + } + } + catch(const Exception& e) + { + OSL_FAIL("Exception caught! : writeBytes(aData);"); + StorageContainer::throwJavaException(e,env); + } +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess + * Method: writeInt + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_NativeStorageAccess_writeInt + (JNIEnv * env, jobject obj_this,jstring name, jstring key, jint v) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "data" ); + aOpLog.logOperation( "writeInt" ); + + DataLogFile aDataLog( env, name, "data" ); + write_to_storage_stream( env, name, key, v, &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream( env, name, key, v ); +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HStorageMap.cxx b/connectivity/source/drivers/hsqldb/HStorageMap.cxx new file mode 100644 index 000000000..d10ee29a6 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HStorageMap.cxx @@ -0,0 +1,360 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HStorageMap.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/embed/XTransactionBroadcaster.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <uno/mapping.hxx> +#include <algorithm> + +namespace connectivity::hsqldb +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::embed; + using namespace ::com::sun::star::io; + + StreamHelper::StreamHelper(const Reference< XStream>& _xStream) + : m_xStream(_xStream) + { + } + + StreamHelper::~StreamHelper() + { + try + { + m_xStream.clear(); + m_xSeek.clear(); + if ( m_xInputStream.is() ) + { + m_xInputStream->closeInput(); + m_xInputStream.clear(); + } + // this is done implicitly by the closing of the input stream + else if ( m_xOutputStream.is() ) + { + m_xOutputStream->closeOutput(); + try + { + ::comphelper::disposeComponent(m_xOutputStream); + } + catch(const DisposedException&) + { + } + catch(const Exception&) + { + OSL_FAIL("Could not dispose OutputStream"); + } + m_xOutputStream.clear(); + } + } + catch(const Exception&) + { + OSL_FAIL("Exception caught!"); + } + } + + Reference< XInputStream> const & StreamHelper::getInputStream() + { + if ( !m_xInputStream.is() ) + m_xInputStream = m_xStream->getInputStream(); + return m_xInputStream; + } + + Reference< XOutputStream> const & StreamHelper::getOutputStream() + { + if ( !m_xOutputStream.is() ) + m_xOutputStream = m_xStream->getOutputStream(); + return m_xOutputStream; + } + + Reference< XSeekable> const & StreamHelper::getSeek() + { + if ( !m_xSeek.is() ) + m_xSeek.set(m_xStream,UNO_QUERY); + return m_xSeek; + } + + css::uno::Reference<css::embed::XStorage> StorageData::mapStorage() + const + { + css::uno::Environment env(css::uno::Environment::getCurrent()); + if (!(env.is() && storageEnvironment.is())) { + throw css::uno::RuntimeException("cannot get environments"); + } + if (env.get() == storageEnvironment.get()) { + return storage; + } else { + css::uno::Mapping map(storageEnvironment, env); + if (!map.is()) { + throw css::uno::RuntimeException("cannot get mapping"); + } + css::uno::Reference<css::embed::XStorage> mapped; + map.mapInterface( + reinterpret_cast<void **>(&mapped), storage.get(), + cppu::UnoType<css::embed::XStorage>::get()); + return mapped; + } + } + + static TStorages& lcl_getStorageMap() + { + static TStorages s_aMap; + return s_aMap; + } + + static OUString lcl_getNextCount() + { + static sal_Int32 s_nCount = 0; + return OUString::number(s_nCount++); + } + + OUString StorageContainer::removeURLPrefix(const OUString& _sURL,const OUString& _sFileURL) + { + return _sURL.copy(_sFileURL.getLength()+1); + } + + OUString StorageContainer::removeOldURLPrefix(const OUString& _sURL) + { + OUString sRet = _sURL; +#if defined(_WIN32) + sal_Int32 nIndex = sRet.lastIndexOf('\\'); +#else + sal_Int32 nIndex = sRet.lastIndexOf('/'); +#endif + if ( nIndex != -1 ) + { + sRet = _sURL.copy(nIndex+1); + } + return sRet; + + } + /*****************************************************************************/ + /* convert jstring to rtl_uString */ + + OUString StorageContainer::jstring2ustring(JNIEnv * env, jstring jstr) + { + if (env->ExceptionCheck()) + { + env->ExceptionClear(); + OSL_FAIL("ExceptionClear"); + } + OUString aStr; + if ( jstr ) + { + jboolean bCopy(true); + const jchar* pChar = env->GetStringChars(jstr,&bCopy); + jsize len = env->GetStringLength(jstr); + aStr = OUString( + reinterpret_cast<sal_Unicode const *>(pChar), len); + + if(bCopy) + env->ReleaseStringChars(jstr,pChar); + } + + if (env->ExceptionCheck()) + { + env->ExceptionClear(); + OSL_FAIL("ExceptionClear"); + } + return aStr; + } + + + OUString StorageContainer::registerStorage(const Reference< XStorage>& _xStorage,const OUString& _sURL) + { + OSL_ENSURE(_xStorage.is(),"Storage is NULL!"); + TStorages& rMap = lcl_getStorageMap(); + // check if the storage is already in our map + TStorages::const_iterator aFind = std::find_if(rMap.begin(),rMap.end(), + [&_xStorage] (const TStorages::value_type& storage) { + return storage.second.mapStorage() == _xStorage; + }); + + if ( aFind == rMap.end() ) + { + aFind = rMap.insert(TStorages::value_type(lcl_getNextCount(), {_xStorage, css::uno::Environment::getCurrent(), _sURL, TStreamMap()})).first; + } + + return aFind->first; + } + + TStorages::mapped_type StorageContainer::getRegisteredStorage(const OUString& _sKey) + { + TStorages::mapped_type aRet; + TStorages& rMap = lcl_getStorageMap(); + TStorages::const_iterator aFind = rMap.find(_sKey); + OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!"); + if ( aFind != rMap.end() ) + aRet = aFind->second; + + return aRet; + } + + OUString StorageContainer::getRegisteredKey(const Reference< XStorage>& _xStorage) + { + OUString sKey; + OSL_ENSURE(_xStorage.is(),"Storage is NULL!"); + TStorages& rMap = lcl_getStorageMap(); + // check if the storage is already in our map + TStorages::const_iterator aFind = std::find_if(rMap.begin(),rMap.end(), + [&_xStorage] (const TStorages::value_type& storage) { + return storage.second.mapStorage() == _xStorage; + }); + + if ( aFind != rMap.end() ) + sKey = aFind->first; + return sKey; + } + + void StorageContainer::revokeStorage(const OUString& _sKey,const Reference<XTransactionListener>& _xListener) + { + TStorages& rMap = lcl_getStorageMap(); + TStorages::iterator aFind = rMap.find(_sKey); + if ( aFind == rMap.end() ) + return; + + try + { + if ( _xListener.is() ) + { + Reference<XTransactionBroadcaster> xBroad(aFind->second.mapStorage(),UNO_QUERY); + if ( xBroad.is() ) + xBroad->removeTransactionListener(_xListener); + Reference<XTransactedObject> xTrans(aFind->second.mapStorage(),UNO_QUERY); + if ( xTrans.is() ) + xTrans->commit(); + } + } + catch(const Exception&) + { + } + rMap.erase(aFind); + } + + TStreamMap::mapped_type StorageContainer::registerStream(JNIEnv * env,jstring name, jstring key,sal_Int32 _nMode) + { + TStreamMap::mapped_type pHelper; + TStorages& rMap = lcl_getStorageMap(); + OUString sKey = jstring2ustring(env,key); + TStorages::iterator aFind = rMap.find(sKey); + OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!"); + if ( aFind != rMap.end() ) + { + TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(sKey); + auto storage = aStoragePair.mapStorage(); + OSL_ENSURE(storage.is(),"No Storage available!"); + if ( storage.is() ) + { + OUString sOrgName = StorageContainer::jstring2ustring(env,name); + OUString sName = removeURLPrefix(sOrgName,aStoragePair.url); + TStreamMap::iterator aStreamFind = aFind->second.streams.find(sName); + OSL_ENSURE( aStreamFind == aFind->second.streams.end(),"A Stream was already registered for this object!"); + if ( aStreamFind != aFind->second.streams.end() ) + { + pHelper = aStreamFind->second; + } + else + { + try + { + try + { + pHelper = std::make_shared<StreamHelper>(storage->openStreamElement(sName,_nMode)); + } + catch(const Exception&) + { + OUString sStrippedName = removeOldURLPrefix(sOrgName); + + if ( (_nMode & ElementModes::WRITE) != ElementModes::WRITE ) + { + bool bIsStream = true; + try + { + bIsStream = storage->isStreamElement(sStrippedName); + } + catch(const Exception&) + { + bIsStream = false; + } + if ( !bIsStream ) + return pHelper; // readonly file without data stream + } + pHelper = std::make_shared<StreamHelper>(storage->openStreamElement( sStrippedName, _nMode ) ); + } + aFind->second.streams.emplace(sName,pHelper); + } + catch(const Exception& e) + { + SAL_WARN( "connectivity.hsqldb", "[HSQLDB-SDBC] caught an exception while opening a stream\n" + "Name: " << sName + << "\nMode: 0x" << ( _nMode < 16 ? "0" : "") + << std::hex << _nMode ); + StorageContainer::throwJavaException(e,env); + } + } + } + } + return pHelper; + } + + void StorageContainer::revokeStream( JNIEnv * env,jstring name, jstring key) + { + TStorages& rMap = lcl_getStorageMap(); + TStorages::iterator aFind = rMap.find(jstring2ustring(env,key)); + OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!"); + if ( aFind != rMap.end() ) + aFind->second.streams.erase(removeURLPrefix(jstring2ustring(env,name),aFind->second.url)); + } + + TStreamMap::mapped_type StorageContainer::getRegisteredStream( JNIEnv * env,jstring name, jstring key) + { + TStreamMap::mapped_type pRet; + TStorages& rMap = lcl_getStorageMap(); + TStorages::const_iterator aFind = rMap.find(jstring2ustring(env,key)); + OSL_ENSURE(aFind != rMap.end(),"Storage could not be found in list!"); + if ( aFind != rMap.end() ) + { + TStreamMap::const_iterator aStreamFind = aFind->second.streams.find(removeURLPrefix(jstring2ustring(env,name),aFind->second.url)); + if ( aStreamFind != aFind->second.streams.end() ) + pRet = aStreamFind->second; + } + + return pRet; + } + + void StorageContainer::throwJavaException(const Exception& _aException,JNIEnv * env) + { + if (env->ExceptionCheck()) + env->ExceptionClear(); + SAL_WARN("connectivity.hsqldb", "forwarding Exception: " << _aException ); + OString cstr( OUStringToOString(_aException.Message, RTL_TEXTENCODING_JAVA_UTF8 ) ); + env->ThrowNew(env->FindClass("java/io/IOException"), cstr.getStr()); + } + +} // namespace + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTable.cxx b/connectivity/source/drivers/hsqldb/HTable.cxx new file mode 100644 index 000000000..f8dee57c5 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTable.cxx @@ -0,0 +1,390 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HTable.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <comphelper/property.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/TKeys.hxx> +#include <connectivity/TIndexes.hxx> +#include <hsqldb/HColumns.hxx> +#include <TConnection.hxx> + +#include <tools/diagnose_ex.h> + + +using namespace ::comphelper; +using namespace connectivity::hsqldb; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables, + const Reference< XConnection >& _xConnection) + :OTableHelper(_pTables,_xConnection,true) +{ + // we create a new table here, so we should have all the rights or ;-) + m_nPrivileges = Privilege::DROP | + Privilege::REFERENCE | + Privilege::ALTER | + Privilege::CREATE | + Privilege::READ | + Privilege::DELETE | + Privilege::UPDATE | + Privilege::INSERT | + Privilege::SELECT; + construct(); +} + +OHSQLTable::OHSQLTable( sdbcx::OCollection* _pTables, + const Reference< XConnection >& _xConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName, + sal_Int32 _nPrivileges + ) : OTableHelper( _pTables, + _xConnection, + true, + Name, + Type, + Description, + SchemaName, + CatalogName) + , m_nPrivileges(_nPrivileges) +{ + construct(); +} + +void OHSQLTable::construct() +{ + OTableHelper::construct(); + if ( !isNew() ) + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), PROPERTY_ID_PRIVILEGES,PropertyAttribute::READONLY,&m_nPrivileges, cppu::UnoType<decltype(m_nPrivileges)>::get()); +} + +::cppu::IPropertyArrayHelper* OHSQLTable::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & OHSQLTable::getInfoHelper() +{ + return *static_cast<OHSQLTable_PROP*>(this)->getArrayHelper(isNew() ? 1 : 0); +} + +sdbcx::OCollection* OHSQLTable::createColumns(const ::std::vector< OUString>& _rNames) +{ + OHSQLColumns* pColumns = new OHSQLColumns(*this,m_aMutex,_rNames); + pColumns->setParent(this); + return pColumns; +} + +sdbcx::OCollection* OHSQLTable::createKeys(const ::std::vector< OUString>& _rNames) +{ + return new OKeysHelper(this,m_aMutex,_rNames); +} + +sdbcx::OCollection* OHSQLTable::createIndexes(const ::std::vector< OUString>& _rNames) +{ + return new OIndexesHelper(this,m_aMutex,_rNames); +} + +Sequence< sal_Int8 > OHSQLTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OHSQLTable::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return (isUnoTunnelId<OHSQLTable>(rId)) + ? reinterpret_cast< sal_Int64 >( this ) + : OTable_TYPEDEF::getSomething(rId); +} + +// XAlterTable +void SAL_CALL OHSQLTable::alterColumnByName( const OUString& colName, const Reference< XPropertySet >& descriptor ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed( +#ifdef __GNUC__ + ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed +#else + rBHelper.bDisposed +#endif + ); + + if ( !m_xColumns || !m_xColumns->hasByName(colName) ) + throw NoSuchElementException(colName,*this); + + + if ( !isNew() ) + { + // first we have to check what should be altered + Reference<XPropertySet> xProp; + m_xColumns->getByName(colName) >>= xProp; + // first check the types + sal_Int32 nOldType = 0,nNewType = 0,nOldPrec = 0,nNewPrec = 0,nOldScale = 0,nNewScale = 0; + OUString sOldTypeName, sNewTypeName; + + ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap(); + + // type/typename + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) >>= sOldTypeName; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME))>>= sNewTypeName; + + // and precision and scale + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION))>>= nNewPrec; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale; + + // second: check the "is nullable" value + sal_Int32 nOldNullable = 0,nNewNullable = 0; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable; + + // check also the auto_increment + bool bOldAutoIncrement = false,bAutoIncrement = false; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bOldAutoIncrement; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) >>= bAutoIncrement; + + // now we should look if the name of the column changed + OUString sNewColumnName; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName; + if ( sNewColumnName != colName ) + { + const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); + + OUString sSql = getAlterTableColumnPart() + + " ALTER COLUMN " + + ::dbtools::quoteName(sQuote,colName) + + " RENAME TO " + + ::dbtools::quoteName(sQuote,sNewColumnName); + + executeStatement(sSql); + } + + if ( nOldType != nNewType + || sOldTypeName != sNewTypeName + || nOldPrec != nNewPrec + || nOldScale != nNewScale + || nNewNullable != nOldNullable + || bOldAutoIncrement != bAutoIncrement ) + { + // special handling because they change the type names to distinguish + // if a column should be an auto_increment one + if ( bOldAutoIncrement != bAutoIncrement ) + { + /// TODO: insert special handling for auto increment "IDENTITY" and primary key + } + alterColumnType(nNewType,sNewColumnName,descriptor); + } + + // third: check the default values + OUString sNewDefault,sOldDefault; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sNewDefault; + + if(!sOldDefault.isEmpty()) + { + dropDefaultValue(colName); + if(!sNewDefault.isEmpty() && sOldDefault != sNewDefault) + alterDefaultValue(sNewDefault,sNewColumnName); + } + else if(sOldDefault.isEmpty() && !sNewDefault.isEmpty()) + alterDefaultValue(sNewDefault,sNewColumnName); + + m_xColumns->refresh(); + } + else + { + if(m_xColumns) + { + m_xColumns->dropByName(colName); + m_xColumns->appendByDescriptor(descriptor); + } + } + +} + +void OHSQLTable::alterColumnType(sal_Int32 nNewType,const OUString& _rColName, const Reference<XPropertySet>& _xDescriptor) +{ + OUString sSql = getAlterTableColumnPart() + " ALTER COLUMN "; +#if OSL_DEBUG_LEVEL > 0 + try + { + OUString sDescriptorName; + OSL_ENSURE( _xDescriptor.is() + && ( _xDescriptor->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sDescriptorName ) + && ( sDescriptorName == _rColName ), + "OHSQLTable::alterColumnType: unexpected column name!" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } +#else + (void)_rColName; +#endif + + OHSQLColumn* pColumn = new OHSQLColumn; + Reference<XPropertySet> xProp = pColumn; + ::comphelper::copyProperties(_xDescriptor,xProp); + xProp->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE),makeAny(nNewType)); + + sSql += ::dbtools::createStandardColumnPart(xProp,getConnection()); + executeStatement(sSql); +} + +void OHSQLTable::alterDefaultValue(const OUString& _sNewDefault,const OUString& _rColName) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); + OUString sSql = getAlterTableColumnPart() + + " ALTER COLUMN " + + ::dbtools::quoteName(sQuote,_rColName) + + " SET DEFAULT '" + _sNewDefault + "'"; + + executeStatement(sSql); +} + +void OHSQLTable::dropDefaultValue(const OUString& _rColName) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString( ); + OUString sSql = getAlterTableColumnPart() + + " ALTER COLUMN " + + ::dbtools::quoteName(sQuote,_rColName) + + " DROP DEFAULT"; + + executeStatement(sSql); +} + +OUString OHSQLTable::getAlterTableColumnPart() const +{ + OUString sSql( "ALTER TABLE " ); + + OUString sComposedName( ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InTableDefinitions ) ); + sSql += sComposedName; + + return sSql; +} + +void OHSQLTable::executeStatement(const OUString& _rStatement ) +{ + OUString sSQL = _rStatement; + if(sSQL.endsWith(",")) + sSQL = sSQL.replaceAt(sSQL.getLength()-1, 1, ")"); + + Reference< XStatement > xStmt = getConnection()->createStatement( ); + if ( xStmt.is() ) + { + try { xStmt->execute(sSQL); } + catch( const Exception& ) + { + ::comphelper::disposeComponent(xStmt); + throw; + } + ::comphelper::disposeComponent(xStmt); + } +} + +Sequence< Type > SAL_CALL OHSQLTable::getTypes( ) +{ + if ( m_Type == "VIEW" ) + { + Sequence< Type > aTypes = OTableHelper::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pIter = aTypes.getConstArray(); + const Type* pEnd = pIter + aTypes.getLength(); + for(;pIter != pEnd;++pIter) + { + if( *pIter != cppu::UnoType<XRename>::get()) + { + aOwnTypes.push_back(*pIter); + } + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); + } + return OTableHelper::getTypes(); +} + +// XRename +void SAL_CALL OHSQLTable::rename( const OUString& newName ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed( +#ifdef __GNUC__ + ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed +#else + rBHelper.bDisposed +#endif + ); + + if(!isNew()) + { + OUString sSql = "ALTER "; + if ( m_Type == "VIEW" ) + sSql += " VIEW "; + else + sSql += " TABLE "; + + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(getMetaData(),newName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + + sSql += + ::dbtools::composeTableName( getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InDataManipulation ) + + " RENAME TO " + + ::dbtools::composeTableName( getMetaData(), sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation ); + + executeStatement(sSql); + + ::connectivity::OTable_TYPEDEF::rename(newName); + } + else + ::dbtools::qualifiedNameComponents(getMetaData(),newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InTableDefinitions); +} + + +Any SAL_CALL OHSQLTable::queryInterface( const Type & rType ) +{ + if( m_Type == "VIEW" && rType == cppu::UnoType<XRename>::get()) + return Any(); + + return OTableHelper::queryInterface(rType); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTables.cxx b/connectivity/source/drivers/hsqldb/HTables.cxx new file mode 100644 index 000000000..787af894b --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTables.cxx @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HTables.hxx> +#include <hsqldb/HViews.hxx> +#include <hsqldb/HTable.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <hsqldb/HCatalog.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace ::cppu; +using namespace connectivity::hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace dbtools; + +sdbcx::ObjectType OTables::createObject(const OUString& _rName) +{ + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,_rName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + + Sequence< OUString > sTableTypes(3); + sTableTypes[0] = "VIEW"; + sTableTypes[1] = "TABLE"; + sTableTypes[2] = "%"; // just to be sure to include anything else... + + Any aCatalog; + if ( !sCatalog.isEmpty() ) + aCatalog <<= sCatalog; + Reference< XResultSet > xResult = m_xMetaData->getTables(aCatalog,sSchema,sTable,sTableTypes); + + sdbcx::ObjectType xRet; + if ( xResult.is() ) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + if ( xResult->next() ) // there can be only one table with this name + { + sal_Int32 nPrivileges = ::dbtools::getTablePrivileges( m_xMetaData, sCatalog, sSchema, sTable ); + if ( m_xMetaData->isReadOnly() ) + nPrivileges &= ~( Privilege::INSERT | Privilege::UPDATE | Privilege::DELETE | Privilege::CREATE | Privilege::ALTER | Privilege::DROP ); + + // obtain privileges + OHSQLTable* pRet = new OHSQLTable( this + ,static_cast<OHCatalog&>(m_rParent).getConnection() + ,sTable + ,xRow->getString(4) + ,xRow->getString(5) + ,sSchema + ,sCatalog + ,nPrivileges); + xRet = pRet; + } + ::comphelper::disposeComponent(xResult); + } + + return xRet; +} + +void OTables::impl_refresh( ) +{ + static_cast<OHCatalog&>(m_rParent).refreshTables(); +} + +void OTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference< XPropertySet > OTables::createDescriptor() +{ + return new OHSQLTable(this,static_cast<OHCatalog&>(m_rParent).getConnection()); +} + +// XAppend +sdbcx::ObjectType OTables::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + createTable(descriptor); + return createObject( _rForName ); +} + +// XDrop +void OTables::dropObject(sal_Int32 _nPos,const OUString& _sElementName) +{ + Reference< XInterface > xObject( getObject( _nPos ) ); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew( xObject ); + if (bIsNew) + return; + + Reference< XConnection > xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + + + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,_sElementName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + + OUString aSql( "DROP " ); + + Reference<XPropertySet> xProp(xObject,UNO_QUERY); + bool bIsView; + if((bIsView = (xProp.is() && ::comphelper::getString(xProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) == "VIEW"))) // here we have a view + aSql += "VIEW "; + else + aSql += "TABLE "; + + OUString sComposedName( + ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation ) ); + aSql += sComposedName; + Reference< XStatement > xStmt = xConnection->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + // if no exception was thrown we must delete it from the views + if ( bIsView ) + { + HViews* pViews = static_cast<HViews*>(static_cast<OHCatalog&>(m_rParent).getPrivateViews()); + if ( pViews && pViews->hasByName(_sElementName) ) + pViews->dropByNameImpl(_sElementName); + } +} + +void OTables::createTable( const Reference< XPropertySet >& descriptor ) +{ + Reference< XConnection > xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor,xConnection); + + Reference< XStatement > xStmt = xConnection->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + +void OTables::appendNew(const OUString& _rsNewTable) +{ + insertElement(_rsNewTable,nullptr); + + // notify our container listeners + ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_rsNewTable), Any(), Any()); + OInterfaceIteratorHelper2 aListenerLoop(m_aContainerListeners); + while (aListenerLoop.hasMoreElements()) + static_cast<XContainerListener*>(aListenerLoop.next())->elementInserted(aEvent); +} + +OUString OTables::getNameForObject(const sdbcx::ObjectType& _xObject) +{ + OSL_ENSURE(_xObject.is(),"OTables::getNameForObject: Object is NULL!"); + return ::dbtools::composeTableName( m_xMetaData, _xObject, ::dbtools::EComposeRule::InDataManipulation, false ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTerminateListener.cxx b/connectivity/source/drivers/hsqldb/HTerminateListener.cxx new file mode 100644 index 000000000..df325efb7 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTerminateListener.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 "HTerminateListener.hxx" +#include <hsqldb/HDriver.hxx> + + +namespace connectivity +{ + + using namespace hsqldb; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + +// XEventListener +void SAL_CALL OConnectionController::disposing( const EventObject& /*Source*/ ) +{ +} + +// XTerminateListener +void SAL_CALL OConnectionController::queryTermination( const EventObject& /*aEvent*/ ) +{ + m_pDriver->flushConnections(); +} + +void SAL_CALL OConnectionController::notifyTermination( const EventObject& /*aEvent*/ ) +{ + m_pDriver->shutdownConnections(); +} + + +} // namespace connectivity + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTerminateListener.hxx b/connectivity/source/drivers/hsqldb/HTerminateListener.hxx new file mode 100644 index 000000000..62e8ec79d --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTerminateListener.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_HSQLDB_HTERMINATELISTENER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_HSQLDB_HTERMINATELISTENER_HXX + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/frame/XTerminateListener.hpp> + + +namespace connectivity +{ + + + namespace hsqldb + { + class ODriverDelegator; + class OConnectionController : public ::cppu::WeakImplHelper< css::frame::XTerminateListener > + { + ODriverDelegator* m_pDriver; + protected: + virtual ~OConnectionController() override {m_pDriver = nullptr;} + public: + explicit OConnectionController(ODriverDelegator* _pDriver) : m_pDriver(_pDriver){} + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& aEvent ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& aEvent ) override; + }; + } + +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_HSQLDB_HTERMINATELISTENER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HTools.cxx b/connectivity/source/drivers/hsqldb/HTools.cxx new file mode 100644 index 000000000..b9854c01c --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HTools.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HTools.hxx> + + +namespace connectivity::hsqldb +{ + + void HTools::appendTableFilterCrit( OUStringBuffer& _inout_rBuffer, const OUString& _rCatalog, + const OUString& _rSchema, const OUString& _rName, bool _bShortForm ) + { + _inout_rBuffer.append( " WHERE " ); + if ( !_rCatalog.isEmpty() ) + { + _inout_rBuffer.appendAscii( _bShortForm ? "TABLE_CAT" : "TABLE_CATALOG" ); + _inout_rBuffer.append( " = '" ); + _inout_rBuffer.append ( _rCatalog ); + _inout_rBuffer.append( "' AND " ); + } + if ( !_rSchema.isEmpty() ) + { + _inout_rBuffer.appendAscii( _bShortForm ? "TABLE_SCHEM" : "TABLE_SCHEMA" ); + _inout_rBuffer.append( " = '" ); + _inout_rBuffer.append ( _rSchema ); + _inout_rBuffer.append( "' AND " ); + } + _inout_rBuffer.append( "TABLE_NAME = '" ); + _inout_rBuffer.append ( _rName ); + _inout_rBuffer.append( "'" ); + } + + +} // namespace connectivity::hsqldb + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HUser.cxx b/connectivity/source/drivers/hsqldb/HUser.cxx new file mode 100644 index 000000000..2ed0c0626 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HUser.cxx @@ -0,0 +1,328 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HUser.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/PrivilegeObject.hpp> +#include <TConnection.hxx> +#include <strings.hrc> + +using namespace connectivity; +using namespace connectivity::hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OHSQLUser::OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection) : connectivity::sdbcx::OUser(true) + ,m_xConnection(_xConnection) +{ + construct(); +} + +OHSQLUser::OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const OUString& Name + ) : connectivity::sdbcx::OUser(Name,true) + ,m_xConnection(_xConnection) +{ + construct(); +} + +void OHSQLUser::refreshGroups() +{ +} + +OUserExtend::OUserExtend( const css::uno::Reference< css::sdbc::XConnection >& _xConnection) : OHSQLUser(_xConnection) +{ + construct(); +} + +void OUserExtend::construct() +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), PROPERTY_ID_PASSWORD,0,&m_Password,::cppu::UnoType<OUString>::get()); +} + +cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new cppu::OPropertyArrayHelper(aProps); +} + +cppu::IPropertyArrayHelper & OUserExtend::getInfoHelper() +{ + return *OUserExtend_PROP::getArrayHelper(); +} +typedef connectivity::sdbcx::OUser_BASE OUser_BASE_RBHELPER; + +sal_Int32 SAL_CALL OHSQLUser::getPrivileges( const OUString& objName, sal_Int32 objType ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + sal_Int32 nRights,nRightsWithGrant; + findPrivilegesAndGrantPrivileges(objName,objType,nRights,nRightsWithGrant); + return nRights; +} + +void OHSQLUser::findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant) +{ + nRightsWithGrant = nRights = 0; + // first we need to create the sql stmt to select the privs + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(xMeta,objName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation); + Reference<XResultSet> xRes; + switch(objType) + { + case PrivilegeObject::TABLE: + case PrivilegeObject::VIEW: + { + Any aCatalog; + if ( !sCatalog.isEmpty() ) + aCatalog <<= sCatalog; + xRes = xMeta->getTablePrivileges(aCatalog,sSchema,sTable); + } + break; + + case PrivilegeObject::COLUMN: + { + Any aCatalog; + if ( !sCatalog.isEmpty() ) + aCatalog <<= sCatalog; + xRes = xMeta->getColumnPrivileges(aCatalog,sSchema,sTable,"%"); + } + break; + } + + if ( !xRes.is() ) + return; + + static const char sYes [] = "YES"; + + nRightsWithGrant = nRights = 0; + + Reference<XRow> xCurrentRow(xRes,UNO_QUERY); + while( xCurrentRow.is() && xRes->next() ) + { + OUString sGrantee = xCurrentRow->getString(5); + OUString sPrivilege = xCurrentRow->getString(6); + OUString sGrantable = xCurrentRow->getString(7); + + if (!m_Name.equalsIgnoreAsciiCase(sGrantee)) + continue; + + if (sPrivilege.equalsIgnoreAsciiCase("SELECT")) + { + nRights |= Privilege::SELECT; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::SELECT; + } + else if (sPrivilege.equalsIgnoreAsciiCase("INSERT")) + { + nRights |= Privilege::INSERT; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::INSERT; + } + else if (sPrivilege.equalsIgnoreAsciiCase("UPDATE")) + { + nRights |= Privilege::UPDATE; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::UPDATE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("DELETE")) + { + nRights |= Privilege::DELETE; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::DELETE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("READ")) + { + nRights |= Privilege::READ; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::READ; + } + else if (sPrivilege.equalsIgnoreAsciiCase("CREATE")) + { + nRights |= Privilege::CREATE; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::CREATE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("ALTER")) + { + nRights |= Privilege::ALTER; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::ALTER; + } + else if (sPrivilege.equalsIgnoreAsciiCase("REFERENCE")) + { + nRights |= Privilege::REFERENCE; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::REFERENCE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("DROP")) + { + nRights |= Privilege::DROP; + if ( sGrantable.equalsIgnoreAsciiCase(sYes) ) + nRightsWithGrant |= Privilege::DROP; + } + } + ::comphelper::disposeComponent(xRes); +} + +sal_Int32 SAL_CALL OHSQLUser::getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + sal_Int32 nRights,nRightsWithGrant; + findPrivilegesAndGrantPrivileges(objName,objType,nRights,nRightsWithGrant); + return nRightsWithGrant; +} + +void SAL_CALL OHSQLUser::grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) +{ + if ( objType != PrivilegeObject::TABLE ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_PRIVILEGE_NOT_GRANTED)); + ::dbtools::throwGenericSQLException(sError,*this); + } // if ( objType != PrivilegeObject::TABLE ) + + + ::osl::MutexGuard aGuard(m_aMutex); + + OUString sPrivs = getPrivilegeString(objPrivileges); + if(!sPrivs.isEmpty()) + { + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sGrant = "GRANT " + sPrivs + + " ON " + ::dbtools::quoteTableName(xMeta,objName,::dbtools::EComposeRule::InDataManipulation) + + " TO " + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), m_Name); + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if(xStmt.is()) + xStmt->execute(sGrant); + ::comphelper::disposeComponent(xStmt); + } +} + +void SAL_CALL OHSQLUser::revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) +{ + if ( objType != PrivilegeObject::TABLE ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_PRIVILEGE_NOT_REVOKED)); + ::dbtools::throwGenericSQLException(sError,*this); + } // if ( objType != PrivilegeObject::TABLE ) + + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + OUString sPrivs = getPrivilegeString(objPrivileges); + if(!sPrivs.isEmpty()) + { + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sGrant = "REVOKE " + sPrivs + + " ON " + ::dbtools::quoteTableName(xMeta,objName,::dbtools::EComposeRule::InDataManipulation) + + " FROM " + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), m_Name); + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if(xStmt.is()) + xStmt->execute(sGrant); + ::comphelper::disposeComponent(xStmt); + } +} + +// XUser +void SAL_CALL OHSQLUser::changePassword( const OUString& /*oldPassword*/, const OUString& newPassword ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + + if( m_Name != xMeta->getUserName() ) + { + ::dbtools::throwGenericSQLException("HSQLDB can only change password of the current user.", *this); + } + + OUString sAlterPwd = "SET PASSWORD " + + ::dbtools::quoteName(xMeta->getIdentifierQuoteString(), newPassword); + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if ( xStmt.is() ) + { + xStmt->execute(sAlterPwd); + ::comphelper::disposeComponent(xStmt); + } +} + +OUString OHSQLUser::getPrivilegeString(sal_Int32 nRights) +{ + OUString sPrivs; + if((nRights & Privilege::INSERT) == Privilege::INSERT) + sPrivs += "INSERT"; + + if((nRights & Privilege::DELETE) == Privilege::DELETE) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "DELETE"; + } + + if((nRights & Privilege::UPDATE) == Privilege::UPDATE) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "UPDATE"; + } + + if((nRights & Privilege::ALTER) == Privilege::ALTER) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "ALTER"; + } + + if((nRights & Privilege::SELECT) == Privilege::SELECT) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "SELECT"; + } + + if((nRights & Privilege::REFERENCE) == Privilege::REFERENCE) + { + if(!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "REFERENCES"; + } + + return sPrivs; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HUsers.cxx b/connectivity/source/drivers/hsqldb/HUsers.cxx new file mode 100644 index 000000000..40d1f5243 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HUsers.cxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <hsqldb/HUsers.hxx> +#include <hsqldb/HUser.hxx> +#include <connectivity/sdbcx/IRefreshable.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::hsqldb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OUsers::OUsers( ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + connectivity::sdbcx::IRefreshableUsers* _pParent) + : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + ,m_xConnection(_xConnection) + ,m_pParent(_pParent) +{ +} + + +sdbcx::ObjectType OUsers::createObject(const OUString& _rName) +{ + return new OHSQLUser(m_xConnection,_rName); +} + +void OUsers::impl_refresh() +{ + m_pParent->refreshUsers(); +} + +Reference< XPropertySet > OUsers::createDescriptor() +{ + OUserExtend* pNew = new OUserExtend(m_xConnection); + return pNew; +} + +// XAppend +sdbcx::ObjectType OUsers::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString( ); + OUString sPassword; + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) >>= sPassword; + OUString aSql = "GRANT USAGE ON * TO " + + ::dbtools::quoteName(aQuote,_rForName) + " @\"%\" "; + if ( !sPassword.isEmpty() ) + { + aSql += " IDENTIFIED BY '" + sPassword + "'"; + } + + Reference< XStatement > xStmt = m_xConnection->createStatement( ); + if(xStmt.is()) + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + + return createObject( _rForName ); +} + +// XDrop +void OUsers::dropObject(sal_Int32 /*nPos*/,const OUString& _sElementName) +{ + OUString aSql( "REVOKE ALL ON * FROM " ); + OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString( ); + aSql += ::dbtools::quoteName(aQuote,_sElementName); + + Reference< XStatement > xStmt = m_xConnection->createStatement( ); + if(xStmt.is()) + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HView.cxx b/connectivity/source/drivers/hsqldb/HView.cxx new file mode 100644 index 000000000..0a09ec0d2 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HView.cxx @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <hsqldb/HView.hxx> +#include <hsqldb/HTools.hxx> + +#include <propertyids.hxx> + +#include <connectivity/dbtools.hxx> + +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <cppuhelper/exc_hlp.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/sharedunocomponent.hxx> + + +namespace connectivity::hsqldb +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::sdbc::SQLException; + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::lang::WrappedTargetException; + using ::com::sun::star::sdbc::XResultSet; + using ::com::sun::star::sdbc::XStatement; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::sdbc::XRow; + + HView::HView( const Reference< XConnection >& _rxConnection, bool _bCaseSensitive, + const OUString& _rSchemaName, const OUString& _rName ) + :HView_Base( _bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName, OUString() ) + ,m_xConnection( _rxConnection ) + { + } + + + HView::~HView() + { + } + + + IMPLEMENT_FORWARD_XINTERFACE2( HView, HView_Base, HView_IBASE ) + IMPLEMENT_FORWARD_XTYPEPROVIDER2( HView, HView_Base, HView_IBASE ) + + + void SAL_CALL HView::alterCommand( const OUString& _rNewCommand ) + { + // not really atomic ... as long as we do not have something like + // ALTER VIEW <name> TO <command> + // in HSQL, we need to do it this way ... + // + // I can imagine scenarios where this fails, e.g. when dropping the view + // succeeds, re-creating it fails, some other thread alters a table which + // the view was based on, and then we try to restore the view with the + // original command, which then fails, too. + // + // However, there's not much chance to prevent this kind of errors without + // backend support. + + OUString sQualifiedName( ::dbtools::composeTableName( + m_xMetaData, m_CatalogName, m_SchemaName, m_Name, true, ::dbtools::EComposeRule::InDataManipulation ) ); + + ::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW ); + + // create a statement which can be used to re-create the original view, in case + // dropping it succeeds, but creating it with a new statement fails + OUStringBuffer aRestoreCommand; + aRestoreCommand.append( "CREATE VIEW " ); + aRestoreCommand.append ( sQualifiedName ); + aRestoreCommand.append( " AS " ); + aRestoreCommand.append ( impl_getCommand_throwSQLException() ); + OUString sRestoreCommand( aRestoreCommand.makeStringAndClear() ); + + bool bDropSucceeded( false ); + try + { + // drop the existing view + OUString aCommand ="DROP VIEW " + sQualifiedName; + xStatement->execute( aCommand ); + bDropSucceeded = true; + + // create a new one with the same name + aCommand = "CREATE VIEW " + sQualifiedName + " AS " + _rNewCommand; + xStatement->execute( aCommand ); + } + catch( const SQLException& ) + { + if ( bDropSucceeded ) + // drop succeeded, but creation failed -> re-create the view with the original + // statement + xStatement->execute( sRestoreCommand ); + throw; + } + catch( const RuntimeException& ) + { + if ( bDropSucceeded ) + xStatement->execute( sRestoreCommand ); + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + if ( bDropSucceeded ) + xStatement->execute( sRestoreCommand ); + } + } + + + void SAL_CALL HView::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const + { + if ( _nHandle == PROPERTY_ID_COMMAND ) + { + // retrieve the very current command, don't rely on the base classes cached value + // (which we initialized empty, anyway) + _rValue <<= impl_getCommand_wrapSQLException(); + return; + } + + HView_Base::getFastPropertyValue( _rValue, _nHandle ); + } + + OUString HView::impl_getCommand() const + { + OUStringBuffer aCommand; + aCommand.append( "SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.SYSTEM_VIEWS " ); + HTools::appendTableFilterCrit( aCommand, m_CatalogName, m_SchemaName, m_Name, false ); + ::utl::SharedUNOComponent< XStatement > xStatement; xStatement.set( m_xConnection->createStatement(), UNO_QUERY_THROW ); + Reference< XResultSet > xResult( xStatement->executeQuery( aCommand.makeStringAndClear() ), css::uno::UNO_SET_THROW ); + if ( !xResult->next() ) + { + // hmm. There is no view the name as we know it. Can only mean some other instance + // dropped this view meanwhile... + throw DisposedException(); + } + + Reference< XRow > xRow( xResult, UNO_QUERY_THROW ); + return xRow->getString( 1 ); + } + + OUString HView::impl_getCommand_wrapSQLException() const + { + OUString sCommand; + + try + { + sCommand = impl_getCommand(); + } + catch( const RuntimeException& ) + { + throw; + } + catch( const SQLException& e ) + { + throw WrappedTargetException( e.Message, static_cast< XAlterView* >( const_cast< HView* >( this ) ), ::cppu::getCaughtException() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + + return sCommand; + } + + OUString HView::impl_getCommand_throwSQLException() const + { + OUString sCommand; + + try + { + sCommand = impl_getCommand(); + } + catch( const RuntimeException& ) + { + throw; + } + catch( const SQLException& ) + { + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.hsqldb"); + } + + return sCommand; + } + +} // namespace connectivity::hsqldb + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/HViews.cxx b/connectivity/source/drivers/hsqldb/HViews.cxx new file mode 100644 index 000000000..e67a9fa14 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/HViews.cxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <hsqldb/HTables.hxx> +#include <hsqldb/HViews.hxx> +#include <hsqldb/HView.hxx> +#include <hsqldb/HCatalog.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; + +using namespace ::cppu; +using namespace connectivity; +using namespace connectivity::hsqldb; +using namespace css::uno; +using namespace css::beans; +using namespace css::sdbcx; +using namespace css::sdbc; +using namespace css::container; +using namespace css::lang; +using namespace dbtools; +typedef connectivity::sdbcx::OCollection OCollection_TYPE; + + +HViews::HViews( const Reference< XConnection >& _rxConnection, ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector ) + :sdbcx::OCollection( _rParent, true, _rMutex, _rVector ) + ,m_xConnection( _rxConnection ) + ,m_xMetaData( _rxConnection->getMetaData() ) + ,m_bInDrop( false ) +{ +} + + +sdbcx::ObjectType HViews::createObject(const OUString& _rName) +{ + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, + _rName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + return new HView( m_xConnection, isCaseSensitive(), sSchema, sTable ); +} + + +void HViews::impl_refresh( ) +{ + static_cast<OHCatalog&>(m_rParent).refreshTables(); +} + +void HViews::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference< XPropertySet > HViews::createDescriptor() +{ + Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + connectivity::sdbcx::OView* pNew = new connectivity::sdbcx::OView(true, xConnection->getMetaData()); + return pNew; +} + +// XAppend +sdbcx::ObjectType HViews::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + createView(descriptor); + return createObject( _rForName ); +} + +// XDrop +void HViews::dropObject(sal_Int32 _nPos,const OUString& /*_sElementName*/) +{ + if ( m_bInDrop ) + return; + + Reference< XInterface > xObject( getObject( _nPos ) ); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew( xObject ); + if (!bIsNew) + { + OUString aSql( "DROP VIEW" ); + + Reference<XPropertySet> xProp(xObject,UNO_QUERY); + aSql += ::dbtools::composeTableName( m_xMetaData, xProp, ::dbtools::EComposeRule::InTableDefinitions, true ); + + Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + Reference< XStatement > xStmt = xConnection->createStatement( ); + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + +void HViews::dropByNameImpl(const OUString& elementName) +{ + m_bInDrop = true; + OCollection_TYPE::dropByName(elementName); + m_bInDrop = false; +} + +void HViews::createView( const Reference< XPropertySet >& descriptor ) +{ + Reference<XConnection> xConnection = static_cast<OHCatalog&>(m_rParent).getConnection(); + + OUString sCommand; + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND)) >>= sCommand; + + OUString aSql = "CREATE VIEW " + + ::dbtools::composeTableName( m_xMetaData, descriptor, ::dbtools::EComposeRule::InTableDefinitions, true ) + + " AS " + sCommand; + + Reference< XStatement > xStmt = xConnection->createStatement( ); + if ( xStmt.is() ) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + + // insert the new view also in the tables collection + OTables* pTables = static_cast<OTables*>(static_cast<OHCatalog&>(m_rParent).getPrivateTables()); + if ( pTables ) + { + OUString sName = ::dbtools::composeTableName( m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false ); + pTables->appendNew(sName); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/Hservices.cxx b/connectivity/source/drivers/hsqldb/Hservices.cxx new file mode 100644 index 000000000..5ca8a0962 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/Hservices.cxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <hsqldb/HDriver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::hsqldb; +using css::uno::Reference; +using css::uno::Sequence; +using css::lang::XSingleServiceFactory; +using css::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* hsqldb_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + ODriverDelegator::getImplementationName_Static(), + ODriverDelegator::getSupportedServiceNames_Static(), + ODriverDelegator_CreateInstance, ::cppu::createSingleFactory) + ; + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx b/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx new file mode 100644 index 000000000..3e8461a95 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/StorageFileAccess.cxx @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H +#include <config.h> +#endif +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <hsqldb/HStorageMap.hxx> +#include <osl/diagnose.h> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::connectivity::hsqldb; + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess + * Method: isStreamElement + * Signature: (Ljava/lang/String;Ljava/lang/String;)Z + */ +extern "C" SAL_JNI_EXPORT jboolean JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_isStreamElement + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name) +{ + TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key)); + auto storage = aStoragePair.mapStorage(); + if ( storage.is() ) + { + try + { + OUString sName = StorageContainer::jstring2ustring(env,name); + try + { + OUString sOldName = StorageContainer::removeOldURLPrefix(sName); + if ( storage->isStreamElement(sOldName) ) + { + try + { + storage->renameElement(sOldName,StorageContainer::removeURLPrefix(sName,aStoragePair.url)); + } + catch(const Exception&) + { + } + } + } + catch(const NoSuchElementException&) + { + } + catch(const IllegalArgumentException&) + { + } + return storage->isStreamElement(StorageContainer::removeURLPrefix(sName,aStoragePair.url)); + } + catch(const NoSuchElementException&) + { + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("connectivity.hsqldb", "forwarding"); + if (env->ExceptionCheck()) + env->ExceptionClear(); + } + } + return JNI_FALSE; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess + * Method: removeElement + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_removeElement + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + { + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sName = StorageContainer::jstring2ustring(env,name); + } +#endif + TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key)); + auto storage = aStoragePair.mapStorage(); + if ( !storage.is() ) + return; + + try + { + storage->removeElement(StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,name),aStoragePair.url)); + } + catch(const NoSuchElementException&) + { + if (env->ExceptionCheck()) + env->ExceptionClear(); + } + catch(const Exception& e) + { + TOOLS_WARN_EXCEPTION("connectivity.hsqldb", ""); + StorageContainer::throwJavaException(e,env); + } +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess + * Method: renameElement + * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_renameElement + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring oldname, jstring newname) +{ +#ifdef HSQLDB_DBG + { + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sNewName = StorageContainer::jstring2ustring(env,newname); + OUString sOldName = StorageContainer::jstring2ustring(env,oldname); + } +#endif + TStorages::mapped_type aStoragePair = StorageContainer::getRegisteredStorage(StorageContainer::jstring2ustring(env,key)); + auto storage = aStoragePair.mapStorage(); + if ( !storage.is() ) + return; + + try + { + storage->renameElement( + StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,oldname),aStoragePair.url), + StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,newname),aStoragePair.url) + ); +#ifdef HSQLDB_DBG + { + OUString sNewName = StorageContainer::removeURLPrefix(StorageContainer::jstring2ustring(env,newname),aStoragePair.first.second); + OSL_ENSURE(aStoragePair.first.first->isStreamElement(sNewName),"Stream could not be renamed"); + } +#endif + } + catch(const NoSuchElementException&) + { + } + catch(const Exception& e) + { + OSL_FAIL("Exception caught! : Java_com_sun_star_sdbcx_comp_hsqldb_StorageFileAccess_renameElement"); + StorageContainer::throwJavaException(e,env); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx b/connectivity/source/drivers/hsqldb/StorageNativeInputStream.cxx new file mode 100644 index 000000000..bdafac4ee --- /dev/null +++ b/connectivity/source/drivers/hsqldb/StorageNativeInputStream.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 . + */ + + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H +#include <config.h> +#endif +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp> +#include <hsqldb/HStorageAccess.hxx> +#include <hsqldb/HStorageMap.hxx> + +#include <osl/diagnose.h> +#include "accesslog.hxx" + +#include <limits> + + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::connectivity::hsqldb; + +/*****************************************************************************/ +/* exception macros */ + +#define ThrowException(env, type, msg) { \ + env->ThrowNew(env->FindClass(type), msg); } +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: openStream + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_openStream + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jint mode) +{ +#ifdef HSQLDB_DBG + { + OperationLogFile( env, name, "input" ).logOperation( "openStream" ); + LogFile( env, name, "input" ).create(); + } +#endif + StorageContainer::registerStream(env,name,key,mode); +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2 + (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "input" ).logOperation( "read()" ); + + DataLogFile aDataLog( env, name, "input" ); + return read_from_storage_stream( env, obj_this, name, key, &aDataLog ); +#else + return read_from_storage_stream( env, name, key ); +#endif +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2_3BII + (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer, jint off, jint len) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "input" ).logOperation( "read( byte[], int, int )" ); + + DataLogFile aDataLog( env, name, "input" ); + return read_from_storage_stream_into_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog ); +#else + (void)obj_this; + return read_from_storage_stream_into_buffer(env, name,key,buffer,off,len); +#endif +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: close + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_close + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "input" ); + aOpLog.logOperation( "close" ); + aOpLog.close(); + + LogFile aDataLog( env, name, "input" ); + aDataLog.close(); +#endif + StorageContainer::revokeStream(env,name,key); +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: skip + * Signature: (Ljava/lang/String;Ljava/lang/String;J)J + */ +extern "C" SAL_JNI_EXPORT jlong JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_skip + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jlong n) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "input" ).logOperation( "skip()" ); +#endif + + if ( n < 0 ) + ThrowException( env, + "java/io/IOException", + "n < 0"); + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper.get(),"No stream helper!"); + if ( pHelper ) + { + Reference<XInputStream> xIn = pHelper->getInputStream(); + if ( xIn.is() ) + { + try + { + sal_Int64 tmpLongVal = n; + sal_Int32 tmpIntVal; + + try + { + do { + if (tmpLongVal >= std::numeric_limits<sal_Int64>::max() ) + tmpIntVal = std::numeric_limits<sal_Int32>::max(); + else // Casting is safe here. + tmpIntVal = static_cast<sal_Int32>(tmpLongVal); + + tmpLongVal -= tmpIntVal; + + xIn->skipBytes(tmpIntVal); + + } while (tmpLongVal > 0); + } + catch(const Exception&) + { + } + + return n - tmpLongVal; + } + catch(const Exception& e) + { + OSL_FAIL("Exception caught! : skip();"); + StorageContainer::throwJavaException(e,env); + } + } + } + else + { + ThrowException( env, + "java/io/IOException", + "Stream is not valid"); + } + return 0; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: available + * Signature: (Ljava/lang/String;Ljava/lang/String;)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_available + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "input" ); + aOpLog.logOperation( "available" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + OSL_ENSURE(pHelper.get(),"No stream helper!"); + Reference<XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference<XInputStream>(); + if ( xIn.is() ) + { + try + { + jint nAvailable = xIn->available(); +#ifdef HSQLDB_DBG + aOpLog.logReturn( nAvailable ); +#endif + return nAvailable; + } + catch(const Exception& e) + { + OSL_FAIL("Exception caught! : available();"); + StorageContainer::throwJavaException(e,env); + } + } + else + { + ThrowException( env, + "java/io/IOException", + "Stream is not valid"); + } + return 0; +} + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream + * Method: read + * Signature: (Ljava/lang/String;Ljava/lang/String;[B)I + */ +extern "C" SAL_JNI_EXPORT jint JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeInputStream_read__Ljava_lang_String_2Ljava_lang_String_2_3B + (JNIEnv * env, jobject /*obj_this*/,jstring key, jstring name, jbyteArray buffer) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "input" ); + aOpLog.logOperation( "read( byte[] )" ); + + DataLogFile aDataLog( env, name, "input" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XInputStream> xIn = pHelper ? pHelper->getInputStream() : Reference< XInputStream>(); + OSL_ENSURE(xIn.is(),"Input stream is NULL!"); + jint nBytesRead = 0; + if ( xIn.is() ) + { + jsize nLen = env->GetArrayLength(buffer); + Sequence< ::sal_Int8 > aData(nLen); + + try + { + nBytesRead = xIn->readBytes(aData,nLen); + } + catch(const Exception& e) + { + OSL_FAIL("Exception caught! : skip();"); + StorageContainer::throwJavaException(e,env); + } + + // Casting bytesRead to an int is okay, since the user can + // only pass in an integer length to read, so the bytesRead + // must <= len. + + if (nBytesRead <= 0) { +#ifdef HSQLDB_DBG + aOpLog.logReturn( (jint)-1 ); +#endif + return -1; + } + OSL_ENSURE(nLen >= nBytesRead,"Buffer is too small!"); + OSL_ENSURE(aData.getLength() >= nBytesRead,"Buffer is too small!"); + env->SetByteArrayRegion(buffer, 0, nBytesRead, reinterpret_cast<jbyte*>(&aData[0])); +#ifdef HSQLDB_DBG + aDataLog.write( &aData[0], nBytesRead ); +#endif + } +#ifdef HSQLDB_DBG + aOpLog.logReturn( nBytesRead ); +#endif + return nBytesRead; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx b/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx new file mode 100644 index 000000000..f766696e0 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/StorageNativeOutputStream.cxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cppuhelper/bootstrap.hxx> +#include <osl/diagnose.h> +#include "accesslog.hxx" +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp> +#include <hsqldb/HStorageAccess.hxx> +#include <hsqldb/HStorageMap.hxx> + +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::embed; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::lang; +using namespace ::connectivity::hsqldb; + + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: openStream + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_openStream + (JNIEnv * env, jobject /*obj_this*/, jstring name, jstring key, jint mode) +{ +#ifdef HSQLDB_DBG + { + OperationLogFile( env, name, "output" ).logOperation( "openStream" ); + LogFile( env, name, "output" ).create(); + } +#endif + StorageContainer::registerStream(env,name,key,mode); +} +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: write + * Signature: (Ljava/lang/String;Ljava/lang/String;[BII)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2_3BII + (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer, jint off, jint len) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "write( byte[], int, int )" ); + + DataLogFile aDataLog( env, name, "output" ); + write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, off, len, &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream_from_buffer( env, name, key, buffer, off, len ); +#endif +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: write + * Signature: (Ljava/lang/String;Ljava/lang/String;[B)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2_3B + (JNIEnv * env, jobject obj_this, jstring key, jstring name, jbyteArray buffer) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "write( byte[] )" ); + + DataLogFile aDataLog( env, name, "output" ); + write_to_storage_stream_from_buffer( env, obj_this, name, key, buffer, 0, env->GetArrayLength( buffer ), &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream_from_buffer( env, name, key, buffer, 0, env->GetArrayLength( buffer ) ); +#endif +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: close + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_close + (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile aOpLog( env, name, "output" ); + aOpLog.logOperation( "close" ); + + LogFile aDataLog( env, name, "output" ); +#endif + + std::shared_ptr<StreamHelper> pHelper = StorageContainer::getRegisteredStream(env,name,key); + Reference< XOutputStream> xFlush = pHelper ? pHelper->getOutputStream() : Reference< XOutputStream>(); + if ( xFlush.is() ) + try + { + xFlush->flush(); + } + catch(Exception&) + {} + +#ifdef HSQLDB_DBG + aDataLog.close(); + aOpLog.close(); +#endif + StorageContainer::revokeStream(env,name,key); +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: write + * Signature: (Ljava/lang/String;Ljava/lang/String;I)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_write__Ljava_lang_String_2Ljava_lang_String_2I + (JNIEnv * env, jobject obj_this, jstring key, jstring name,jint b) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "write( int )" ); + + DataLogFile aDataLog( env, name, "output" ); + write_to_storage_stream( env, name, key, b, &aDataLog ); +#else + (void)obj_this; + write_to_storage_stream( env, name, key, b ); +#endif +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: flush + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_flush + (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "flush" ); + + OUString sKey = StorageContainer::jstring2ustring(env,key); + OUString sName = StorageContainer::jstring2ustring(env,name); +#else + (void) env; + (void) key; + (void) name; +#endif +} + +/* + * Class: com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream + * Method: sync + * Signature: (Ljava/lang/String;Ljava/lang/String;)V + */ +extern "C" SAL_JNI_EXPORT void JNICALL Java_com_sun_star_sdbcx_comp_hsqldb_StorageNativeOutputStream_sync + (JNIEnv * env, jobject /*obj_this*/, jstring key, jstring name) +{ +#ifdef HSQLDB_DBG + OperationLogFile( env, name, "output" ).logOperation( "sync" ); +#endif + std::shared_ptr< StreamHelper > pStream = StorageContainer::getRegisteredStream( env, name, key ); + Reference< XOutputStream > xFlush = pStream ? pStream->getOutputStream() : Reference< XOutputStream>(); + OSL_ENSURE( xFlush.is(), "StorageNativeOutputStream::sync: could not retrieve an output stream!" ); + if ( xFlush.is() ) + { + try + { + xFlush->flush(); + } + catch(Exception&) + { + OSL_FAIL( "StorageNativeOutputStream::sync: could not flush output stream!" ); + } + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/accesslog.cxx b/connectivity/source/drivers/hsqldb/accesslog.cxx new file mode 100644 index 000000000..f7e0f10ee --- /dev/null +++ b/connectivity/source/drivers/hsqldb/accesslog.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#ifdef HSQLDB_DBG + +#include <map> + +#include "accesslog.hxx" +#include "hsqldb/HStorageMap.hxx" + +#include <osl/thread.h> + +namespace connectivity::hsqldb +{ + typedef std::map<OUString, FILE *> TDebugStreamMap; + TDebugStreamMap& getStreams() + { + static TDebugStreamMap streams; + return streams; + } + + + LogFile::LogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix ) + : m_sFileName(StorageContainer::jstring2ustring(env,streamName) + + "." + OUString::createFromAscii( _pAsciiSuffix ) ) + { + } + + + FILE*& LogFile::getLogFile() + { + FILE*& pLogFile = getStreams()[m_sFileName]; + if ( !pLogFile ) + { + OString sByteLogName = OUStringToOString(m_sFileName,osl_getThreadTextEncoding()); + pLogFile = fopen( sByteLogName.getStr(), "a+" ); + } + return pLogFile; + } + + + void LogFile::writeString( const char* _pString, bool _bEndLine ) + { + FILE* pLogFile = getLogFile(); + fwrite( _pString, sizeof( *_pString ), strlen( _pString ), pLogFile ); + if ( _bEndLine ) + fwrite( "\n", sizeof( *_pString ), strlen( "\n" ), pLogFile ); + fflush( pLogFile ); + } + + + void LogFile::close() + { + fclose( getLogFile() ); + getLogFile() = NULL; + } +} } +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/accesslog.hxx b/connectivity/source/drivers/hsqldb/accesslog.hxx new file mode 100644 index 000000000..a4dc41f2d --- /dev/null +++ b/connectivity/source/drivers/hsqldb/accesslog.hxx @@ -0,0 +1,138 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_HSQLDB_ACCESSLOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_HSQLDB_ACCESSLOG_HXX + +#ifdef HSQLDB_DBG + +#include <jni.h> +#include <rtl/ustring.hxx> +#include <rtl/string.hxx> + +namespace connectivity::hsqldb +{ + class LogFile + { + private: + OUString m_sFileName; + + public: + LogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix ); + + public: + void writeString( const char* _pString, bool _bEndLine = true ); + void create() { getLogFile(); } + virtual void close(); + + protected: + FILE*& getLogFile(); + }; + + class OperationLogFile : public LogFile + { + public: + OperationLogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix ) + :LogFile( env, streamName, ( OString( _pAsciiSuffix ) += ".op" ).getStr() ) + { + } + + void logOperation( const char* _pOp ) + { + writeString( _pOp, true ); + } + + void logOperation( const char* _pOp, jlong _nLongArg ) + { + OString sLine( _pOp ); + sLine += "( "; + sLine += OString::number( _nLongArg ); + sLine += " )"; + writeString( sLine.getStr(), true ); + } + + void logReturn( jlong _nRetVal ) + { + OString sLine( " -> " ); + sLine += OString::number( _nRetVal ); + writeString( sLine.getStr(), true ); + } + + void logReturn( jint _nRetVal ) + { + OString sLine( " -> " ); + sLine += OString::number( _nRetVal ); + writeString( sLine.getStr(), true ); + } + + virtual void close() + { + writeString( "-------------------------------", true ); + writeString( "", true ); + LogFile::close(); + } + }; + + class DataLogFile : public LogFile + { + public: + DataLogFile( JNIEnv* env, jstring streamName, const char* _pAsciiSuffix ) + :LogFile( env, streamName, _pAsciiSuffix ) + { + } + + void write( jint value ) + { + fputc( value, getLogFile() ); + fflush( getLogFile() ); + } + + void write( const sal_Int8* buffer, sal_Int32 bytesRead ) + { + fwrite( buffer, sizeof(sal_Int8), bytesRead, getLogFile() ); + fflush( getLogFile() ); + } + + sal_Int64 seek( sal_Int64 pos ) + { + FILE* pFile = getLogFile(); + fseek( pFile, 0, SEEK_END ); + if ( ftell( pFile ) < pos ) + { + sal_Int8 filler( 0 ); + while ( ftell( pFile ) < pos ) + fwrite( &filler, sizeof( sal_Int8 ), 1, pFile ); + fflush( pFile ); + } + fseek( pFile, pos, SEEK_SET ); + return ftell( pFile ); + } + + sal_Int64 tell() + { + return ftell( getLogFile() ); + } + }; + +} } +#endif + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_HSQLDB_ACCESSLOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/hsqldb/hsqldb.component b/connectivity/source/drivers/hsqldb/hsqldb.component new file mode 100644 index 000000000..ab8318861 --- /dev/null +++ b/connectivity/source/drivers/hsqldb/hsqldb.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="hsqldb" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.sdbcx.comp.hsqldb.Driver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/jdbc/Array.cxx b/connectivity/source/drivers/jdbc/Array.cxx new file mode 100644 index 000000000..d03b01928 --- /dev/null +++ b/connectivity/source/drivers/jdbc/Array.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 <java/sql/Array.hxx> +#include <java/tools.hxx> +#include <osl/diagnose.h> + +using namespace connectivity; + +//************ Class: java.sql.Array + + +jclass java_sql_Array::theClass = nullptr; + +java_sql_Array::~java_sql_Array() +{} + +jclass java_sql_Array::getMyClass() const +{ + // the class must be fetched once, therefore it's static + if( !theClass ) + theClass = findMyClass("java/sql/Array"); + + return theClass; +} + +OUString SAL_CALL java_sql_Array::getBaseTypeName( ) +{ + static jmethodID mID(nullptr); + return callStringMethod("getBaseTypeName",mID); +} + +sal_Int32 SAL_CALL java_sql_Array::getBaseType( ) +{ + static jmethodID mID(nullptr); + return callIntMethod_ThrowSQL("getBaseType", mID); +} + +css::uno::Sequence< css::uno::Any > SAL_CALL java_sql_Array::getArray( const css::uno::Reference< css::container::XNameAccess >& typeMap ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + jobject obj = convertTypeMapToJavaMap(typeMap); + static const char * const cSignature = "(Ljava/util/Map;)[Ljava/lang/Object;"; + static const char * const cMethodName = "getArray"; + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + // submit Java-Call + t.pEnv->CallObjectMethod( object, mID, obj); + ThrowSQLException(t.pEnv,*this); + // and clean up + t.pEnv->DeleteLocalRef(obj); + } //t.pEnv + return css::uno::Sequence< css::uno::Any >(); +} + +css::uno::Sequence< css::uno::Any > SAL_CALL java_sql_Array::getArrayAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + jobject obj = convertTypeMapToJavaMap(typeMap); + static const char * const cSignature = "(IILjava/util/Map;)[Ljava/lang/Object;"; + static const char * const cMethodName = "getArray"; + // submit Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + t.pEnv->CallObjectMethod( object, mID, index,count,obj); + ThrowSQLException(t.pEnv,*this); + // and clean up + t.pEnv->DeleteLocalRef(obj); + } + return css::uno::Sequence< css::uno::Any >(); +} + +css::uno::Reference< css::sdbc::XResultSet > SAL_CALL java_sql_Array::getResultSet( const css::uno::Reference< css::container::XNameAccess >& typeMap ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + // convert Parameter + jobject obj = convertTypeMapToJavaMap(typeMap); + // initialize temporary variable + static const char * const cSignature = "(Ljava/util/Map;)Ljava/sql/ResultSet;"; + static const char * const cMethodName = "getResultSet"; + // submit Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + t.pEnv->CallObjectMethod( object, mID, obj); + ThrowSQLException(t.pEnv,*this); + // and cleanup + t.pEnv->DeleteLocalRef(obj); + } + return nullptr; +} + +css::uno::Reference< css::sdbc::XResultSet > SAL_CALL java_sql_Array::getResultSetAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + // convert parameter + jobject obj = convertTypeMapToJavaMap(typeMap); + // initialize temporary variable + static const char * const cSignature = "(Ljava/util/Map;)Ljava/sql/ResultSet;"; + static const char * const cMethodName = "getResultSetAtIndex"; + // submit Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + t.pEnv->CallObjectMethod( object, mID, index,count,obj); + ThrowSQLException(t.pEnv,*this); + // and cleanup + t.pEnv->DeleteLocalRef(obj); + } + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Blob.cxx b/connectivity/source/drivers/jdbc/Blob.cxx new file mode 100644 index 000000000..adacd5d7c --- /dev/null +++ b/connectivity/source/drivers/jdbc/Blob.cxx @@ -0,0 +1,144 @@ +/* -*- 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 <java/sql/Blob.hxx> +#include <java/io/InputStream.hxx> +#include <connectivity/dbexception.hxx> +#include <osl/diagnose.h> + +#include <string.h> + +using namespace connectivity; + +//************ Class: java.sql.Blob + + +jclass java_sql_Blob::theClass = nullptr; +java_sql_Blob::java_sql_Blob( JNIEnv * pEnv, jobject myObj ) + : java_lang_Object( pEnv, myObj ) +{ + SDBThreadAttach::addRef(); +} +java_sql_Blob::~java_sql_Blob() +{ + SDBThreadAttach::releaseRef(); +} + +jclass java_sql_Blob::getMyClass() const +{ + // the class must be fetched only once, therefore it's static + if( !theClass ) + theClass = findMyClass("java/sql/Blob"); + return theClass; +} + +sal_Int64 SAL_CALL java_sql_Blob::length( ) +{ + jlong out(0); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + // initialize temporary variable + static const char * const cSignature = "()J"; + static const char * const cMethodName = "length"; + // submit Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + out = t.pEnv->CallLongMethod( object, mID ); + ThrowSQLException(t.pEnv,*this); + } //t.pEnv + return static_cast<sal_Int64>(out); +} +css::uno::Sequence< sal_Int8 > SAL_CALL java_sql_Blob::getBytes( sal_Int64 pos, sal_Int32 count ) +{ + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + css::uno::Sequence< sal_Int8 > aSeq; + { + // initialize temporary variable + static const char * const cSignature = "(JI)[B"; + static const char * const cMethodName = "getBytes"; + // submit Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + jbyteArray out = static_cast<jbyteArray>(t.pEnv->CallObjectMethod( object, mID,pos,count)); + ThrowSQLException(t.pEnv,*this); + if(out) + { + jboolean p = false; + aSeq.realloc(t.pEnv->GetArrayLength(out)); + memcpy(aSeq.getArray(),t.pEnv->GetByteArrayElements(out,&p),aSeq.getLength()); + t.pEnv->DeleteLocalRef(out); + } + } //t.pEnv + // WARNING: the caller becomes the owner of the returned pointer + return aSeq; +} + +css::uno::Reference< css::io::XInputStream > SAL_CALL java_sql_Blob::getBinaryStream( ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getBinaryStream","()Ljava/io/InputStream;", mID); + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_io_InputStream( t.pEnv, out ); +} + +sal_Int64 SAL_CALL java_sql_Blob::position( const css::uno::Sequence< sal_Int8 >& pattern, sal_Int64 start ) +{ + jlong out(0); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + // initialize temporary variable + static const char * const cSignature = "([BI)J"; + static const char * const cMethodName = "position"; + // submit Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + // convert Parameter + jbyteArray pByteArray = t.pEnv->NewByteArray(pattern.getLength()); + jbyte * patternData = reinterpret_cast<jbyte *>( + const_cast<sal_Int8 *>(pattern.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between <http://docs.oracle.com/javase/6/docs/ + // technotes/guides/jni/spec/functions.html#wp22933> and + // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/ + // functions.html#wp22933>; work around that difference in a way + // that doesn't trigger loplugin:redundantcast + t.pEnv->SetByteArrayRegion(pByteArray,0,pattern.getLength(),patternData); + out = t.pEnv->CallLongMethod( object, mID, pByteArray,start ); + t.pEnv->DeleteLocalRef(pByteArray); + ThrowSQLException(t.pEnv,*this); + } //t.pEnv + return static_cast<sal_Int64>(out); +} + +sal_Int64 SAL_CALL java_sql_Blob::positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& /*pattern*/, sal_Int64 /*start*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XBlob::positionOfBlob", *this ); + // this was put here in CWS warnings01. The previous implementation was defective, as it did ignore + // the pattern parameter. Since the effort for proper implementation is rather high - we would need + // to translated patter into a byte[] -, we defer this functionality for the moment (hey, it was + // unusable, anyway) + // #i57457# + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Boolean.cxx b/connectivity/source/drivers/jdbc/Boolean.cxx new file mode 100644 index 000000000..acd1e81ef --- /dev/null +++ b/connectivity/source/drivers/jdbc/Boolean.cxx @@ -0,0 +1,43 @@ +/* -*- 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 <java/lang/Boolean.hxx> +using namespace connectivity; + +//************ Class: java.lang.Boolean + + +jclass java_lang_Boolean::theClass = nullptr; + +java_lang_Boolean::~java_lang_Boolean() +{} +jclass java_lang_Boolean::st_getMyClass() +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/lang/Boolean"); + return theClass; +} + +jclass java_lang_Boolean::getMyClass() const +{ + return st_getMyClass(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/CallableStatement.cxx b/connectivity/source/drivers/jdbc/CallableStatement.cxx new file mode 100644 index 000000000..0994c827e --- /dev/null +++ b/connectivity/source/drivers/jdbc/CallableStatement.cxx @@ -0,0 +1,354 @@ +/* -*- 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 <java/sql/CallableStatement.hxx> +#include <java/tools.hxx> +#include <java/sql/Array.hxx> +#include <java/sql/Clob.hxx> +#include <java/sql/Blob.hxx> +#include <java/sql/Connection.hxx> +#include <java/sql/Ref.hxx> +#include <java/sql/Timestamp.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/sequence.hxx> + +#include <string.h> + +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; + + +IMPLEMENT_SERVICE_INFO(java_sql_CallableStatement,"com.sun.star.sdbcx.ACallableStatement","com.sun.star.sdbc.CallableStatement"); + + +//************ Class: java.sql.CallableStatement + +java_sql_CallableStatement::java_sql_CallableStatement( JNIEnv * pEnv, java_sql_Connection& _rCon,const OUString& sql ) + : java_sql_PreparedStatement( pEnv, _rCon, sql ) +{ +} + +java_sql_CallableStatement::~java_sql_CallableStatement() +{ +} + + +Any SAL_CALL java_sql_CallableStatement::queryInterface( const Type & rType ) +{ + Any aRet = java_sql_PreparedStatement::queryInterface(rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< css::sdbc::XRow*>(this),static_cast< css::sdbc::XOutParameters*>(this)); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL java_sql_CallableStatement::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<css::sdbc::XRow>::get(), + cppu::UnoType<css::sdbc::XOutParameters>::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),java_sql_PreparedStatement::getTypes()); +} + +sal_Bool SAL_CALL java_sql_CallableStatement::wasNull( ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + return callBooleanMethod( "wasNull", mID ); +} + +sal_Bool SAL_CALL java_sql_CallableStatement::getBoolean( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "getBoolean", mID,columnIndex ); +} +sal_Int8 SAL_CALL java_sql_CallableStatement::getByte( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jbyte (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallByteMethod; + return callMethodWithIntArg<jbyte>(pCallMethod,"getByte","(I)B",mID,columnIndex); +} +Sequence< sal_Int8 > SAL_CALL java_sql_CallableStatement::getBytes( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + Sequence< sal_Int8 > aSeq; + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jbyteArray out = static_cast<jbyteArray>(callObjectMethodWithIntArg(t.pEnv,"getBytes","(I)[B", mID, columnIndex)); + if (out) + { + jboolean p = false; + aSeq.realloc(t.pEnv->GetArrayLength(out)); + memcpy(aSeq.getArray(),t.pEnv->GetByteArrayElements(out,&p),aSeq.getLength()); + t.pEnv->DeleteLocalRef(out); + } + return aSeq; +} +css::util::Date SAL_CALL java_sql_CallableStatement::getDate( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getDate","(I)Ljava/sql/Date;", mID, columnIndex); + return out ? static_cast <css::util::Date>(java_sql_Date( t.pEnv, out )) : css::util::Date(); +} +double SAL_CALL java_sql_CallableStatement::getDouble( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + double (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallDoubleMethod; + return callMethodWithIntArg<double>(pCallMethod,"getDouble","(I)D",mID,columnIndex); +} + +float SAL_CALL java_sql_CallableStatement::getFloat( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jfloat (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallFloatMethod; + return callMethodWithIntArg<jfloat>(pCallMethod,"getFloat","(I)F",mID,columnIndex); +} + +sal_Int32 SAL_CALL java_sql_CallableStatement::getInt( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + return callIntMethodWithIntArg_ThrowSQL("getInt",mID,columnIndex); +} + +sal_Int64 SAL_CALL java_sql_CallableStatement::getLong( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jlong (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallLongMethod; + return callMethodWithIntArg<jlong>(pCallMethod,"getLong","(I)J",mID,columnIndex); +} + +Any SAL_CALL java_sql_CallableStatement::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callObjectMethodWithIntArg(t.pEnv,"getObject","(I)Ljava/lang/Object;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return Any(); +} + +sal_Int16 SAL_CALL java_sql_CallableStatement::getShort( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jshort (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallShortMethod; + return callMethodWithIntArg<jshort>(pCallMethod,"getShort","(I)S",mID,columnIndex); +} + +OUString SAL_CALL java_sql_CallableStatement::getString( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getString",mID,columnIndex); +} + + css::util::Time SAL_CALL java_sql_CallableStatement::getTime( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getTime","(I)Ljava/sql/Time;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out ? static_cast <css::util::Time> (java_sql_Time( t.pEnv, out )) : css::util::Time(); +} + + css::util::DateTime SAL_CALL java_sql_CallableStatement::getTimestamp( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getTimestamp","(I)Ljava/sql/Timestamp;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out ? static_cast <css::util::DateTime> (java_sql_Timestamp( t.pEnv, out )) : css::util::DateTime(); +} + +void SAL_CALL java_sql_CallableStatement::registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + createStatement(t.pEnv); + + // initialize temporary variable + static const char * const cSignature = "(IILjava/lang/String;)V"; + static const char * const cMethodName = "registerOutParameter"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + // Convert Parameter + jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,typeName)); + t.pEnv->CallVoidMethod( object, mID, parameterIndex,sqlType,str.get()); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } +} +void SAL_CALL java_sql_CallableStatement::registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + createStatement(t.pEnv); + // initialize temporary variable + static const char * const cSignature = "(III)V"; + static const char * const cMethodName = "registerOutParameter"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + t.pEnv->CallVoidMethod( object, mID, parameterIndex,sqlType,scale); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } +} + +jclass java_sql_CallableStatement::theClass = nullptr; + +jclass java_sql_CallableStatement::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/CallableStatement"); + return theClass; +} + +Reference< css::io::XInputStream > SAL_CALL java_sql_CallableStatement::getBinaryStream( sal_Int32 columnIndex ) +{ + Reference< css::sdbc::XBlob > xBlob = getBlob(columnIndex); + return xBlob.is() ? xBlob->getBinaryStream() : Reference< css::io::XInputStream >(); +} +Reference< css::io::XInputStream > SAL_CALL java_sql_CallableStatement::getCharacterStream( sal_Int32 columnIndex ) +{ + Reference< css::sdbc::XClob > xClob = getClob(columnIndex); + return xClob.is() ? xClob->getCharacterStream() : Reference< css::io::XInputStream >(); +} + +Reference< css::sdbc::XArray > SAL_CALL java_sql_CallableStatement::getArray( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getArray","(I)Ljava/sql/Array;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_Array( t.pEnv, out ); +} + +Reference< css::sdbc::XClob > SAL_CALL java_sql_CallableStatement::getClob( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getClob","(I)Ljava/sql/Clob;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_Clob( t.pEnv, out ); +} +Reference< css::sdbc::XBlob > SAL_CALL java_sql_CallableStatement::getBlob( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getBlob","(I)Ljava/sql/Blob;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_Blob( t.pEnv, out ); +} + +Reference< css::sdbc::XRef > SAL_CALL java_sql_CallableStatement::getRef( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getRef","(I)Ljava/sql/Ref;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_Ref( t.pEnv, out ); +} + +void SAL_CALL java_sql_CallableStatement::acquire() throw() +{ + java_sql_PreparedStatement::acquire(); +} + +void SAL_CALL java_sql_CallableStatement::release() throw() +{ + java_sql_PreparedStatement::release(); +} + +void java_sql_CallableStatement::createStatement(JNIEnv* /*_pEnv*/) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + if( !(t.pEnv && !object) ) + return; + + // initialize temporary variable + static const char * const cMethodName = "prepareCall"; + // execute Java-Call + jobject out = nullptr; + // convert Parameter + jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,m_sSqlStatement)); + + static jmethodID mID = [&]() + { + static const char * const cSignature = "(Ljava/lang/String;II)Ljava/sql/CallableStatement;"; + return t.pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature ); + }(); + if( mID ){ + out = t.pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID, str.get() ,m_nResultSetType,m_nResultSetConcurrency); + } //mID + else + { + static const char * const cSignature2 = "(Ljava/lang/String;)Ljava/sql/CallableStatement;"; + static jmethodID mID2 = t.pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature2 );OSL_ENSURE(mID2,"Unknown method id!"); + if( mID2 ){ + out = t.pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID2, str.get() ); + } //mID + } + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + + if ( out ) + object = t.pEnv->NewGlobalRef( out ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Class.cxx b/connectivity/source/drivers/jdbc/Class.cxx new file mode 100644 index 000000000..98d37fbcc --- /dev/null +++ b/connectivity/source/drivers/jdbc/Class.cxx @@ -0,0 +1,70 @@ +/* -*- 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 <java/lang/Class.hxx> +#include <rtl/ustring.hxx> + +using namespace connectivity; + +//************ Class: java.lang.Class + + +jclass java_lang_Class::theClass = nullptr; + +java_lang_Class::~java_lang_Class() +{} + +jclass java_lang_Class::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/lang/Class"); + return theClass; +} + +java_lang_Class * java_lang_Class::forName( const OUString& _par0 ) +{ + jobject out(nullptr); + SDBThreadAttach t; + + { + OString sClassName = OUStringToOString(_par0, RTL_TEXTENCODING_JAVA_UTF8); + sClassName = sClassName.replace('.','/'); + out = t.pEnv->FindClass(sClassName.getStr()); + ThrowSQLException(t.pEnv,nullptr); + } //t.pEnv + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_lang_Class( t.pEnv, out ); +} + +jobject java_lang_Class::newInstanceObject() +{ + SDBThreadAttach t; + auto const id = t.pEnv->GetMethodID(static_cast<jclass>(object), "<init>", "()V"); + if (id == nullptr) { + ThrowSQLException(t.pEnv, nullptr); + } + auto const obj = t.pEnv->NewObject(static_cast<jclass>(object), id); + if (obj == nullptr) { + ThrowSQLException(t.pEnv, nullptr); + } + return obj; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Clob.cxx b/connectivity/source/drivers/jdbc/Clob.cxx new file mode 100644 index 000000000..135512d5a --- /dev/null +++ b/connectivity/source/drivers/jdbc/Clob.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 <java/sql/Clob.hxx> +#include <java/tools.hxx> +#include <java/io/Reader.hxx> +#include <connectivity/dbexception.hxx> +#include <osl/diagnose.h> + +using namespace connectivity; + +//************ Class: java.sql.Clob + + +jclass java_sql_Clob::theClass = nullptr; + +java_sql_Clob::java_sql_Clob( JNIEnv * pEnv, jobject myObj ) + : java_lang_Object( pEnv, myObj ) +{ + SDBThreadAttach::addRef(); +} +java_sql_Clob::~java_sql_Clob() +{ + SDBThreadAttach::releaseRef(); +} + +jclass java_sql_Clob::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/Clob"); + return theClass; +} + +sal_Int64 SAL_CALL java_sql_Clob::length( ) +{ + jlong out(0); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + // initialize temporary variable + static const char * const cSignature = "()J"; + static const char * const cMethodName = "length"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + out = t.pEnv->CallLongMethod( object, mID ); + ThrowSQLException(t.pEnv,*this); + } //t.pEnv + return static_cast<sal_Int64>(out); +} + +OUString SAL_CALL java_sql_Clob::getSubString( sal_Int64 pos, sal_Int32 subStringLength ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + OUString aStr; + { + // initialize temporary variable + static const char * const cSignature = "(JI)Ljava/lang/String;"; + static const char * const cMethodName = "getSubString"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + jstring out = static_cast<jstring>(t.pEnv->CallObjectMethod( object, mID,pos,subStringLength)); + ThrowSQLException(t.pEnv,*this); + aStr = JavaString2String(t.pEnv,out); + } //t.pEnv + // WARNING: the caller becomes the owner of the returned pointer + return aStr; +} + +css::uno::Reference< css::io::XInputStream > SAL_CALL java_sql_Clob::getCharacterStream( ) +{ + SDBThreadAttach t; + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getCharacterStream","()Ljava/io/Reader;", mID); + + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_io_Reader( t.pEnv, out ); +} + +sal_Int64 SAL_CALL java_sql_Clob::position( const OUString& searchstr, sal_Int32 start ) +{ + jlong out(0); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + jvalue args[1]; + // convert Parameter + args[0].l = convertwchar_tToJavaString(t.pEnv,searchstr); + // initialize temporary Variable + static const char * const cSignature = "(Ljava/lang/String;I)J"; + static const char * const cMethodName = "position"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + out = t.pEnv->CallLongMethod( object, mID, args[0].l,start ); + ThrowSQLException(t.pEnv,*this); + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + } //t.pEnv + return static_cast<sal_Int64>(out); +} + +sal_Int64 SAL_CALL java_sql_Clob::positionOfClob( const css::uno::Reference< css::sdbc::XClob >& /*pattern*/, sal_Int64 /*start*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XClob::positionOfClob", *this ); + // this was put here in CWS warnings01. The previous implementation was defective, as it did ignore + // the pattern parameter. Since the effort for proper implementation is rather high - we would need + // to translated patter into a byte[] -, we defer this functionality for the moment (hey, it was + // unusable, anyway) + // 2005-11-15 / #i57457# / frank.schoenheit@sun.com + return 0; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/ConnectionLog.cxx b/connectivity/source/drivers/jdbc/ConnectionLog.cxx new file mode 100644 index 000000000..96a82fb61 --- /dev/null +++ b/connectivity/source/drivers/jdbc/ConnectionLog.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 <java/sql/ConnectionLog.hxx> + +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> + +#include <stdio.h> + + +namespace connectivity::java::sql { + + + namespace + { + sal_Int32 lcl_getFreeID( ConnectionLog::ObjectType _eType ) + { + static oslInterlockedCount s_nCounts[ ConnectionLog::ObjectTypeCount ] = { 0, 0 }; + return osl_atomic_increment( s_nCounts + _eType ); + } + } + + ConnectionLog::ConnectionLog( const ::comphelper::EventLogger& _rDriverLog ) + :ConnectionLog_Base( _rDriverLog ) + ,m_nObjectID( lcl_getFreeID( CONNECTION ) ) + { + } + + + ConnectionLog::ConnectionLog( const ConnectionLog& _rSourceLog ) + :ConnectionLog_Base( _rSourceLog ) + ,m_nObjectID( _rSourceLog.m_nObjectID ) + { + } + + + ConnectionLog::ConnectionLog( const ConnectionLog& _rSourceLog, ConnectionLog::ObjectType _eType ) + :ConnectionLog_Base( _rSourceLog ) + ,m_nObjectID( lcl_getFreeID( _eType ) ) + { + } + + +} // namespace connectivity::java::sql + + +namespace comphelper::log::convert +{ + + + using ::com::sun::star::util::Date; + using ::com::sun::star::util::Time; + using ::com::sun::star::util::DateTime; + + + OUString convertLogArgToString( const Date& _rDate ) + { + char buffer[ 30 ]; + const size_t buffer_size = sizeof( buffer ); + snprintf( buffer, buffer_size, "%04i-%02i-%02i", + static_cast<int>(_rDate.Year), static_cast<int>(_rDate.Month), static_cast<int>(_rDate.Day) ); + return OUString::createFromAscii( buffer ); + } + + + OUString convertLogArgToString( const css::util::Time& _rTime ) + { + char buffer[ 30 ]; + const size_t buffer_size = sizeof( buffer ); + snprintf( buffer, buffer_size, "%02i:%02i:%02i.%09i", + static_cast<int>(_rTime.Hours), static_cast<int>(_rTime.Minutes), static_cast<int>(_rTime.Seconds), static_cast<int>(_rTime.NanoSeconds) ); + return OUString::createFromAscii( buffer ); + } + + + OUString convertLogArgToString( const DateTime& _rDateTime ) + { + char buffer[ sizeof("-32768-65535-65535 65535:65535:65535.4294967295") ]; + // reserve enough space for hypothetical max length + const size_t buffer_size = sizeof( buffer ); + snprintf( buffer, buffer_size, "%04" SAL_PRIdINT32 "-%02" SAL_PRIuUINT32 "-%02" SAL_PRIuUINT32 " %02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ".%09" SAL_PRIuUINT32, + static_cast<sal_Int32>(_rDateTime.Year), static_cast<sal_uInt32>(_rDateTime.Month), static_cast<sal_uInt32>(_rDateTime.Day), + static_cast<sal_uInt32>(_rDateTime.Hours), static_cast<sal_uInt32>(_rDateTime.Minutes), static_cast<sal_uInt32>(_rDateTime.Seconds), _rDateTime.NanoSeconds ); + return OUString::createFromAscii( buffer ); + } + + +} // comphelper::log::convert + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/ContextClassLoader.cxx b/connectivity/source/drivers/jdbc/ContextClassLoader.cxx new file mode 100644 index 000000000..50e6bc632 --- /dev/null +++ b/connectivity/source/drivers/jdbc/ContextClassLoader.cxx @@ -0,0 +1,111 @@ +/* -*- 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 <java/ContextClassLoader.hxx> +#include <java/lang/Object.hxx> + + +namespace connectivity::jdbc +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + + using ::connectivity::java_lang_Object; + + ContextClassLoaderScope::ContextClassLoaderScope( JNIEnv& environment, const GlobalRef< jobject >& newClassLoader, + const ::comphelper::EventLogger& _rLoggerForErrors, const Reference< XInterface >& _rxErrorContext ) + :m_environment( environment ) + ,m_currentThread( environment ) + ,m_oldContextClassLoader( environment ) + ,m_setContextClassLoaderMethod( nullptr ) + { + if ( !newClassLoader.is() ) + return; + + do // artificial loop for easier flow control + { + + LocalRef< jclass > threadClass( m_environment ); + threadClass.set( m_environment.FindClass( "java/lang/Thread" ) ); + if ( !threadClass.is() ) + break; + + jmethodID currentThreadMethod( m_environment.GetStaticMethodID( + threadClass.get(), "currentThread", "()Ljava/lang/Thread;" ) ); + if ( currentThreadMethod == nullptr ) + break; + + m_currentThread.set( m_environment.CallStaticObjectMethod( threadClass.get(), currentThreadMethod ) ); + if ( !m_currentThread.is() ) + break; + + jmethodID getContextClassLoaderMethod( m_environment.GetMethodID( + threadClass.get(), "getContextClassLoader", "()Ljava/lang/ClassLoader;" ) ); + if ( getContextClassLoaderMethod == nullptr ) + break; + m_oldContextClassLoader.set( m_environment.CallObjectMethod( m_currentThread.get(), getContextClassLoaderMethod ) ); + LocalRef< jthrowable > throwable( m_environment, m_environment.ExceptionOccurred() ); + if ( throwable.is() ) + break; + + m_setContextClassLoaderMethod = m_environment.GetMethodID( + threadClass.get(), "setContextClassLoader", "(Ljava/lang/ClassLoader;)V" ); + if ( m_setContextClassLoaderMethod == nullptr ) + break; + + } + while ( false ); + + if ( !isActive() ) + { + java_lang_Object::ThrowLoggedSQLException( _rLoggerForErrors, &environment, _rxErrorContext ); + return; + } + + // set the new class loader + m_environment.CallObjectMethod( m_currentThread.get(), m_setContextClassLoaderMethod, newClassLoader.get() ); + LocalRef< jthrowable > throwable( m_environment, m_environment.ExceptionOccurred() ); + if ( throwable.is() ) + { + m_currentThread.reset(); + m_setContextClassLoaderMethod = nullptr; + java_lang_Object::ThrowLoggedSQLException( _rLoggerForErrors, &environment, _rxErrorContext ); + } + } + + + ContextClassLoaderScope::~ContextClassLoaderScope() + { + if ( isActive() ) + { + LocalRef< jobject > currentThread( m_currentThread.env(), m_currentThread.release() ); + jmethodID setContextClassLoaderMethod( m_setContextClassLoaderMethod ); + m_setContextClassLoaderMethod = nullptr; + + m_environment.CallObjectMethod( currentThread.get(), setContextClassLoaderMethod, m_oldContextClassLoader.get() ); + m_environment.ExceptionClear(); + } + } + +} // namespace connectivity::jdbc + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/DatabaseMetaData.cxx b/connectivity/source/drivers/jdbc/DatabaseMetaData.cxx new file mode 100644 index 000000000..e1918d11c --- /dev/null +++ b/connectivity/source/drivers/jdbc/DatabaseMetaData.cxx @@ -0,0 +1,1459 @@ +/* -*- 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/macros.h> +#include <java/sql/DatabaseMetaData.hxx> +#include <java/sql/Connection.hxx> +#include <java/sql/ResultSet.hxx> +#include <java/sql/SQLException.hxx> +#include <java/tools.hxx> +#include <java/lang/String.hxx> +#include <FDatabaseMetaDataResultSet.hxx> +#include <comphelper/types.hxx> +#include <TPrivilegesResultSet.hxx> +#include <strings.hxx> + +using namespace ::comphelper; + +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; + +jclass java_sql_DatabaseMetaData::theClass = nullptr; + +java_sql_DatabaseMetaData::~java_sql_DatabaseMetaData() +{ + SDBThreadAttach::releaseRef(); +} + +jclass java_sql_DatabaseMetaData::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/DatabaseMetaData"); + return theClass; +} + +java_sql_DatabaseMetaData::java_sql_DatabaseMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rConnection ) + :ODatabaseMetaDataBase( &_rConnection,_rConnection.getConnectionInfo() ) + ,java_lang_Object( pEnv, myObj ) + ,m_pConnection( &_rConnection ) + ,m_aLogger( _rConnection.getLogger() ) +{ + SDBThreadAttach::addRef(); +} + + +Reference< XResultSet > java_sql_DatabaseMetaData::impl_getTypeInfo_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethod( "getTypeInfo", mID ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getCatalogs( ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethod( "getCatalogs", mID ); +} + +OUString java_sql_DatabaseMetaData::impl_getCatalogSeparator_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getCatalogSeparator", mID ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getSchemas( ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethod( "getSchemas", mID ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getColumnPrivileges( + const Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethodWithStrings( "getColumnPrivileges", mID, catalog, schema, table, &columnNamePattern ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getColumns( + const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethodWithStrings( "getColumns", mID, catalog, schemaPattern, tableNamePattern, &columnNamePattern ); +} + + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getTables( + const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const Sequence< OUString >& _types ) +{ + static const char * const cMethodName = "getTables"; + + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, cMethodName ); + + jobject out(nullptr); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)Ljava/sql/ResultSet;"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + OSL_VERIFY( !isExceptionOccurred(t.pEnv) ); + jvalue args[4]; + + args[3].l = nullptr; + sal_Int32 typeFilterCount = _types.getLength(); + if ( typeFilterCount ) + { + jobjectArray pObjArray = t.pEnv->NewObjectArray( static_cast<jsize>(typeFilterCount), java_lang_String::st_getMyClass(), nullptr ); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + const OUString* typeFilter = _types.getConstArray(); + bool bIncludeAllTypes = false; + for ( sal_Int32 i=0; i<typeFilterCount; ++i, ++typeFilter ) + { + if ( *typeFilter == "%" ) + { + bIncludeAllTypes = true; + break; + } + jstring aT = convertwchar_tToJavaString( t.pEnv, *typeFilter ); + t.pEnv->SetObjectArrayElement( pObjArray, static_cast<jsize>(i), aT ); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + + if ( bIncludeAllTypes ) + { + // the SDBC API allows to pass "%" as table type filter, but in JDBC, "all table types" + // is represented by the table type being <null/> + t.pEnv->DeleteLocalRef( pObjArray ); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + else + { + args[3].l = pObjArray; + } + } + // if we are to display "all catalogs", then respect m_aCatalogRestriction + Any aCatalogFilter( catalog ); + if ( !aCatalogFilter.hasValue() ) + aCatalogFilter = m_pConnection->getCatalogRestriction(); + // similar for schema + Any aSchemaFilter; + if ( schemaPattern == "%" ) + aSchemaFilter = m_pConnection->getSchemaRestriction(); + else + aSchemaFilter <<= schemaPattern; + + args[0].l = aCatalogFilter.hasValue() ? convertwchar_tToJavaString( t.pEnv, ::comphelper::getString( aCatalogFilter ) ) : nullptr; + args[1].l = aSchemaFilter.hasValue() ? convertwchar_tToJavaString( t.pEnv, ::comphelper::getString( aSchemaFilter ) ) : nullptr; + args[2].l = convertwchar_tToJavaString(t.pEnv,tableNamePattern); + out = t.pEnv->CallObjectMethod( object, mID, args[0].l, args[1].l,args[2].l,args[3].l); + jthrowable jThrow = t.pEnv->ExceptionOccurred(); + if ( jThrow ) + t.pEnv->ExceptionClear();// we have to clear the exception here because we want to handle it below + if ( aCatalogFilter.hasValue() ) + { + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + if(args[1].l) + { + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l)); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + if(!tableNamePattern.isEmpty()) + { + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l)); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + //for(INT16 i=0;i<len;i++) + if ( args[3].l ) + { + t.pEnv->DeleteLocalRef( static_cast<jobjectArray>(args[3].l) ); + OSL_VERIFY( !isExceptionOccurred( t.pEnv ) ); + } + + if ( jThrow ) + { + if ( t.pEnv->IsInstanceOf( jThrow,java_sql_SQLException_BASE::st_getMyClass() ) ) + { + java_sql_SQLException_BASE aException( t.pEnv, jThrow ); + SQLException e( aException.getMessage(), + *this, + aException.getSQLState(), + aException.getErrorCode(), + Any() + ); + throw e; + } + } + } + + if ( !out ) + return nullptr; + + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, cMethodName ); + return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getProcedureColumns( + const Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethodWithStrings( "getProcedureColumns", mID, catalog, schemaPattern, procedureNamePattern, &columnNamePattern ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getProcedures( const Any& + catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethodWithStrings( "getProcedures", mID, catalog, schemaPattern, procedureNamePattern ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getVersionColumns( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethodWithStrings( "getVersionColumns", mID, catalog, schema, table ); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxBinaryLiteralLength", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxRowSize( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxRowSize", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxCatalogNameLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxCatalogNameLength", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxCharLiteralLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxCharLiteralLength", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnNameLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxColumnNameLength", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInIndex( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxColumnsInIndex", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxCursorNameLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxCursorNameLength", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxConnections( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxConnections", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInTable( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxColumnsInTable", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxStatementLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxStatementLength", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxTableNameLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxTableNameLength", mID); +} + +sal_Int32 java_sql_DatabaseMetaData::impl_getMaxTablesInSelect_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxTablesInSelect", mID); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getExportedKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethodWithStrings( "getExportedKeys", mID, catalog, schema, table ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getImportedKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethodWithStrings( "getImportedKeys", mID, catalog, schema, table ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getPrimaryKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethodWithStrings( "getPrimaryKeys", mID, catalog, schema, table ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getIndexInfo( + const Any& catalog, const OUString& schema, const OUString& table, + sal_Bool unique, sal_Bool approximate ) +{ + static const char * const cMethodName = "getIndexInfo"; + + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, cMethodName ); + + jobject out(nullptr); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZ)Ljava/sql/ResultSet;"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + jvalue args[5]; + // convert Parameter + args[0].l = catalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(catalog)) : nullptr; + args[1].l = schema.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,schema); + args[2].l = convertwchar_tToJavaString(t.pEnv,table); + args[3].z = unique; + args[4].z = approximate; + out = t.pEnv->CallObjectMethod( object, mID, args[0].l,args[1].l,args[2].l,args[3].z,args[4].z ); + + // and clean up + if(catalog.hasValue()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + if(args[1].l) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l)); + if(!table.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l)); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + if ( !out ) + return nullptr; + + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, cMethodName ); + return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getBestRowIdentifier( + const Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, + sal_Bool nullable ) +{ + static const char * const cMethodName = "getBestRowIdentifier"; + + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, cMethodName ); + + jobject out(nullptr); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZ)Ljava/sql/ResultSet;"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + jvalue args[3]; + // convert Parameter + args[0].l = catalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(catalog)) : nullptr; + args[1].l = schema.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,schema); + args[2].l = convertwchar_tToJavaString(t.pEnv,table); + out = t.pEnv->CallObjectMethod( object, mID, args[0].l,args[1].l,args[2].l,scope,nullable); + + // and cleanup + if(catalog.hasValue()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + if(args[1].l) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l)); + if(!table.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l)); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + + if ( !out ) + return nullptr; + + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, cMethodName ); + return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getTablePrivileges( + const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) +{ + if ( m_pConnection->isIgnoreDriverPrivilegesEnabled() ) + return new OResultSetPrivileges(this,catalog,schemaPattern,tableNamePattern); + + static jmethodID mID(nullptr); + Reference< XResultSet > xReturn( impl_callResultSetMethodWithStrings( "getTablePrivileges", mID, catalog, schemaPattern, tableNamePattern ) ); + + if ( xReturn.is() ) + { + // we have to check the result columns for the tables privileges + Reference< XResultSetMetaDataSupplier > xMetaSup(xReturn,UNO_QUERY); + if ( xMetaSup.is() ) + { + Reference< XResultSetMetaData> xMeta = xMetaSup->getMetaData(); + if ( xMeta.is() && xMeta->getColumnCount() != 7 ) + { + // here we know that the count of column doesn't match + std::map<sal_Int32,sal_Int32> aColumnMatching; + static const OUStringLiteral sPrivs[] = { + "TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "GRANTOR", + "GRANTEE", + "PRIVILEGE", + "IS_GRANTABLE" + }; + + OUString sColumnName; + sal_Int32 nCount = xMeta->getColumnCount(); + for (sal_Int32 i = 1 ; i <= nCount ; ++i) + { + sColumnName = xMeta->getColumnName(i); + for (size_t j = 0 ; j < SAL_N_ELEMENTS(sPrivs); ++j) + { + if ( sPrivs[j] == sColumnName ) + { + aColumnMatching.emplace(i,j+1); + break; + } + } + + } + // fill our own resultset + ODatabaseMetaDataResultSet* pNewPrivRes = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges ); + Reference< XResultSet > xTemp = xReturn; + xReturn = pNewPrivRes; + ODatabaseMetaDataResultSet::ORows aRows; + Reference< XRow > xRow(xTemp,UNO_QUERY); + OUString sValue; + + ODatabaseMetaDataResultSet::ORow aRow(8); + while ( xRow.is() && xTemp->next() ) + { + for (const auto& [nCol, nPriv] : aColumnMatching) + { + sValue = xRow->getString(nCol); + if ( xRow->wasNull() ) + aRow[nPriv] = ODatabaseMetaDataResultSet::getEmptyValue(); + else + aRow[nPriv] = new ORowSetValueDecorator(sValue); + } + + aRows.push_back(aRow); + } + pNewPrivRes->setRows(aRows); + } + } + } + return xReturn; +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getCrossReference( + const Any& primaryCatalog, const OUString& primarySchema, + const OUString& primaryTable, const Any& foreignCatalog, + const OUString& foreignSchema, const OUString& foreignTable ) +{ + static const char * const cMethodName = "getCrossReference"; + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, cMethodName ); + + jobject out(nullptr); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/sql/ResultSet;"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + jvalue args[6]; + // convert Parameter + args[0].l = primaryCatalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(primaryCatalog)) : nullptr; + args[1].l = primarySchema.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,primarySchema); + args[2].l = convertwchar_tToJavaString(t.pEnv,primaryTable); + args[3].l = foreignCatalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(foreignCatalog)) : nullptr; + args[4].l = foreignSchema.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,foreignSchema); + args[5].l = convertwchar_tToJavaString(t.pEnv,foreignTable); + out = t.pEnv->CallObjectMethod( object, mID, args[0].l,args[2].l,args[2].l,args[3].l,args[4].l,args[5].l ); + + // and clean up + if(primaryCatalog.hasValue()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + if(args[1].l) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l)); + if(!primaryTable.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l)); + if(foreignCatalog.hasValue()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[3].l)); + if(args[4].l) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[4].l)); + if(!foreignTable.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[5].l)); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + + if ( !out ) + return nullptr; + + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, cMethodName ); + return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection); +} + + +bool java_sql_DatabaseMetaData::impl_callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) +{ + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName ); + bool out( java_lang_Object::callBooleanMethod(_pMethodName,_inout_MethodID) ); + m_aLogger.log< const char*, bool>( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, out ); + return out; +} + + +OUString java_sql_DatabaseMetaData::impl_callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) +{ + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName ); + + const OUString sReturn( callStringMethod(_pMethodName,_inout_MethodID) ); + if ( m_aLogger.isLoggable( LogLevel::FINEST ) ) + { + OUString sLoggedResult( sReturn ); + if ( sLoggedResult.isEmpty() ) + sLoggedResult = "<empty string>"; + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, sLoggedResult ); + } + + return sReturn; +} + +sal_Int32 java_sql_DatabaseMetaData::impl_callIntMethod_ThrowSQL(const char* _pMethodName, jmethodID& _inout_MethodID) +{ + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName ); + sal_Int32 out( callIntMethod_ThrowSQL(_pMethodName,_inout_MethodID) ); + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, out ); + return out; +} + +sal_Int32 java_sql_DatabaseMetaData::impl_callIntMethod_ThrowRuntime(const char* _pMethodName, jmethodID& _inout_MethodID) +{ + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName ); + sal_Int32 out( callIntMethod_ThrowRuntime(_pMethodName,_inout_MethodID) ); + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, out ); + return out; +} + +bool java_sql_DatabaseMetaData::impl_callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) +{ + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG1, _pMethodName, _nArgument ); + + bool out( callBooleanMethodWithIntArg(_pMethodName,_inout_MethodID,_nArgument) ); + + m_aLogger.log< const char*, bool >( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, _pMethodName, out ); + return out; +} + + +Reference< XResultSet > java_sql_DatabaseMetaData::impl_callResultSetMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) +{ + SDBThreadAttach t; + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD, _pMethodName ); + jobject out(callResultSetMethod(t.env(),_pMethodName,_inout_MethodID)); + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, _pMethodName ); + return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection); +} + + +Reference< XResultSet > java_sql_DatabaseMetaData::impl_callResultSetMethodWithStrings( const char* _pMethodName, jmethodID& _inout_MethodID, + const Any& _rCatalog, const OUString& _rSchemaPattern, const OUString& _rLeastPattern, + const OUString* _pOptionalAdditionalString ) +{ + bool bCatalog = _rCatalog.hasValue(); + OUString sCatalog; + _rCatalog >>= sCatalog; + + bool bSchema = _rSchemaPattern.toChar() != '%'; + + // log the call + if ( m_aLogger.isLoggable( LogLevel::FINEST ) ) + { + OUString sCatalogLog = bCatalog ? sCatalog : OUString( "null" ); + OUString sSchemaLog = bSchema ? _rSchemaPattern : OUString( "null" ); + if ( _pOptionalAdditionalString ) + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG4, _pMethodName, sCatalogLog, sSchemaLog, _rLeastPattern, *_pOptionalAdditionalString ); + else + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG3, _pMethodName, sCatalogLog, sSchemaLog, _rLeastPattern ); + } + + jobject out(nullptr); + + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_sql_DatabaseMetaData::impl_callResultSetMethodWithStrings: no Java environment anymore!" ); + + { + const char* pSignature = _pOptionalAdditionalString + ? "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/sql/ResultSet;" + : "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/sql/ResultSet;"; + // obtain method ID + obtainMethodId_throwSQL(t.pEnv, _pMethodName,pSignature, _inout_MethodID); + + // call method + + { + jvalue args[4]; + // convert parameters + args[0].l = bCatalog ? convertwchar_tToJavaString( t.pEnv, sCatalog ) : nullptr; + args[1].l = bSchema ? convertwchar_tToJavaString( t.pEnv, _rSchemaPattern ) : nullptr; + args[2].l = convertwchar_tToJavaString( t.pEnv, _rLeastPattern ); + args[3].l = _pOptionalAdditionalString ? convertwchar_tToJavaString( t.pEnv, *_pOptionalAdditionalString ) : nullptr; + + // actually do the call + if ( _pOptionalAdditionalString ) + out = t.pEnv->CallObjectMethod( object, _inout_MethodID, args[0].l, args[1].l, args[2].l, args[3].l ); + else + out = t.pEnv->CallObjectMethod( object, _inout_MethodID, args[0].l, args[1].l, args[2].l ); + + // clean up + if ( args[0].l ) + t.pEnv->DeleteLocalRef( static_cast<jstring>(args[0].l) ); + if ( args[1].l ) + t.pEnv->DeleteLocalRef( static_cast<jstring>(args[1].l) ); + if ( args[2].l ) + t.pEnv->DeleteLocalRef( static_cast<jstring>(args[2].l) ); + if ( args[3].l ) + t.pEnv->DeleteLocalRef( static_cast<jstring>(args[3].l) ); + + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } + + if ( !out ) + return nullptr; + + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_SUCCESS, _pMethodName ); + return new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection); +} + + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "doesMaxRowSizeIncludeBlobs", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "storesLowerCaseQuotedIdentifiers", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "storesLowerCaseIdentifiers", mID ); +} + +bool java_sql_DatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "storesMixedCaseQuotedIdentifiers", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "storesMixedCaseIdentifiers", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "storesUpperCaseQuotedIdentifiers", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "storesUpperCaseIdentifiers", mID ); +} + +bool java_sql_DatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsAlterTableWithAddColumn", mID ); +} + +bool java_sql_DatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsAlterTableWithDropColumn", mID ); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxIndexLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxIndexLength", mID); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsNonNullableColumns( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsNonNullableColumns", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getCatalogTerm( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getCatalogTerm", mID ); +} + +OUString java_sql_DatabaseMetaData::impl_getIdentifierQuoteString_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getIdentifierQuoteString", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getExtraNameCharacters( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getExtraNameCharacters", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsDifferentTableCorrelationNames", mID ); +} + +bool java_sql_DatabaseMetaData::impl_isCatalogAtStart_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "isCatalogAtStart", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "dataDefinitionIgnoredInTransactions", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "dataDefinitionCausesTransactionCommit", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsDataManipulationTransactionsOnly", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsDataDefinitionAndDataManipulationTransactions", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsPositionedDelete( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsPositionedDelete", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsPositionedUpdate( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsPositionedUpdate", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsOpenStatementsAcrossRollback", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsOpenStatementsAcrossCommit", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsOpenCursorsAcrossCommit", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsOpenCursorsAcrossRollback", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "supportsTransactionIsolationLevel", mID, level ); +} + +bool java_sql_DatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSchemasInDataManipulation", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsANSI92FullSQL( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsANSI92FullSQL", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsANSI92EntryLevelSQL", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsIntegrityEnhancementFacility", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSchemasInIndexDefinitions", mID ); +} + +bool java_sql_DatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSchemasInTableDefinitions", mID ); +} + +bool java_sql_DatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsCatalogsInTableDefinitions", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsCatalogsInIndexDefinitions", mID ); +} + +bool java_sql_DatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsCatalogsInDataManipulation", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOuterJoins( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsOuterJoins", mID ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getTableTypes( ) +{ + static jmethodID mID(nullptr); + return impl_callResultSetMethod( "getTableTypes", mID ); +} + +sal_Int32 java_sql_DatabaseMetaData::impl_getMaxStatements_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxStatements", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxProcedureNameLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxProcedureNameLength", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxSchemaNameLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxSchemaNameLength", mID); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsTransactions( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsTransactions", mID ); +} + + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::allProceduresAreCallable( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "allProceduresAreCallable", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsStoredProcedures( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsStoredProcedures", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSelectForUpdate( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSelectForUpdate", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::allTablesAreSelectable( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "allTablesAreSelectable", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::isReadOnly( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "isReadOnly", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::usesLocalFiles( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "usesLocalFiles", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::usesLocalFilePerTable( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "usesLocalFilePerTable", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsTypeConversion( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsTypeConversion", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullPlusNonNullIsNull( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "nullPlusNonNullIsNull", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsColumnAliasing( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsColumnAliasing", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsTableCorrelationNames( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsTableCorrelationNames", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsConvert( sal_Int32 fromType, sal_Int32 toType ) +{ + static const char* const pMethodName = "supportsConvert"; + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG2, pMethodName, fromType, toType ); + + bool out( false ); + SDBThreadAttach t; + + { + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, pMethodName,"(II)Z", mID); + out = t.pEnv->CallBooleanMethod( object, mID, fromType, toType ); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + + m_aLogger.log< const char*, bool >( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, pMethodName, out ); + return out; +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsExpressionsInOrderBy", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsGroupBy( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsGroupBy", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsGroupByBeyondSelect", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsGroupByUnrelated( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsGroupByUnrelated", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsMultipleTransactions( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsMultipleTransactions", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsMultipleResultSets( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsMultipleResultSets", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsLikeEscapeClause( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsLikeEscapeClause", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsOrderByUnrelated( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsOrderByUnrelated", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsUnion( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsUnion", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsUnionAll( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsUnionAll", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsMixedCaseIdentifiers", mID ); +} + +bool java_sql_DatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsMixedCaseQuotedIdentifiers", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullsAreSortedAtEnd( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "nullsAreSortedAtEnd", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullsAreSortedAtStart( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "nullsAreSortedAtStart", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullsAreSortedHigh( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "nullsAreSortedHigh", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::nullsAreSortedLow( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "nullsAreSortedLow", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSchemasInProcedureCalls", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSchemasInPrivilegeDefinitions", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsCatalogsInProcedureCalls", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsCatalogsInPrivilegeDefinitions", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsCorrelatedSubqueries", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSubqueriesInComparisons", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSubqueriesInExists( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSubqueriesInExists", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSubqueriesInIns( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSubqueriesInIns", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsSubqueriesInQuantifieds", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsANSI92IntermediateSQL", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getURL( ) +{ + OUString sURL = m_pConnection->getURL(); + if ( sURL.isEmpty() ) + { + static jmethodID mID(nullptr); + sURL = impl_callStringMethod( "getURL", mID ); + } + return sURL; +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getUserName( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getUserName", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getDriverName( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getDriverName", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getDriverVersion( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getDriverVersion", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getDatabaseProductVersion( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getDatabaseProductVersion", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getDatabaseProductName( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getDatabaseProductName", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getProcedureTerm( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getProcedureTerm", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getSchemaTerm( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getSchemaTerm", mID ); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getDriverMajorVersion( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowRuntime("getDriverMajorVersion", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getDefaultTransactionIsolation( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getDefaultTransactionIsolation", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getDriverMinorVersion( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowRuntime("getDriverMinorVersion", mID); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getSQLKeywords( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getSQLKeywords", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getSearchStringEscape( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getSearchStringEscape", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getStringFunctions( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getStringFunctions", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getTimeDateFunctions( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getTimeDateFunctions", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getSystemFunctions( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getSystemFunctions", mID ); +} + +OUString SAL_CALL java_sql_DatabaseMetaData::getNumericFunctions( ) +{ + static jmethodID mID(nullptr); + return impl_callStringMethod( "getNumericFunctions", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsExtendedSQLGrammar", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsCoreSQLGrammar( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsCoreSQLGrammar", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsMinimumSQLGrammar", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsFullOuterJoins( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsFullOuterJoins", mID ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsLimitedOuterJoins( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsLimitedOuterJoins", mID ); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxColumnsInGroupBy", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxColumnsInOrderBy", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxColumnsInSelect( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxColumnsInSelect", mID); +} + +sal_Int32 SAL_CALL java_sql_DatabaseMetaData::getMaxUserNameLength( ) +{ + static jmethodID mID(nullptr); + return impl_callIntMethod_ThrowSQL("getMaxUserNameLength", mID); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsResultSetType( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "supportsResultSetType", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) +{ + static const char* const pMethodName = "supportsResultSetConcurrency"; + m_aLogger.log( LogLevel::FINEST, STR_LOG_META_DATA_METHOD_ARG2, pMethodName, setType, concurrency ); + + bool out( false ); + SDBThreadAttach t; + + { + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, pMethodName,"(II)Z", mID); + out = t.pEnv->CallBooleanMethod( object, mID, setType, concurrency); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + + m_aLogger.log< const char*, bool >( LogLevel::FINEST, STR_LOG_META_DATA_RESULT, pMethodName, out ); + return out; +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "ownUpdatesAreVisible", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::ownDeletesAreVisible( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "ownDeletesAreVisible", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::ownInsertsAreVisible( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "ownInsertsAreVisible", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "othersUpdatesAreVisible", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::othersDeletesAreVisible( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "othersDeletesAreVisible", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::othersInsertsAreVisible( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "othersInsertsAreVisible", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::updatesAreDetected( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "updatesAreDetected", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::deletesAreDetected( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "deletesAreDetected", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::insertsAreDetected( sal_Int32 setType ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethodWithIntArg( "insertsAreDetected", mID, setType ); +} + +sal_Bool SAL_CALL java_sql_DatabaseMetaData::supportsBatchUpdates( ) +{ + static jmethodID mID(nullptr); + return impl_callBooleanMethod( "supportsBatchUpdates", mID ); +} + +Reference< XResultSet > SAL_CALL java_sql_DatabaseMetaData::getUDTs( + const Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, + const Sequence< sal_Int32 >& types ) +{ + jobject out(nullptr); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + + + static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)Ljava/sql/ResultSet;"; + static const char * const cMethodName = "getUDTs"; + // dismiss Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + { + jvalue args[4]; + // initialize temporary Variable + args[0].l = catalog.hasValue() ? convertwchar_tToJavaString(t.pEnv,comphelper::getString(catalog)) : nullptr; + args[1].l = schemaPattern.toChar() == '%' ? nullptr : convertwchar_tToJavaString(t.pEnv,schemaPattern); + args[2].l = convertwchar_tToJavaString(t.pEnv,typeNamePattern); + jintArray pArray = t.pEnv->NewIntArray(types.getLength()); + jint * typesData = reinterpret_cast<jint *>( + const_cast<sal_Int32 *>(types.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between <http://docs.oracle.com/javase/6/docs/ + // technotes/guides/jni/spec/functions.html#wp22933> and + // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/ + // functions.html#wp22933>; work around that difference in a way + // that doesn't trigger loplugin:redundantcast + t.pEnv->SetIntArrayRegion(pArray,0,types.getLength(),typesData); + args[3].l = pArray; + + out = t.pEnv->CallObjectMethod( object, mID, args[0].l, args[1].l,args[2].l,args[3].l); + + if(catalog.hasValue()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + if(!schemaPattern.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l)); + if(!typeNamePattern.isEmpty()) + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[2].l)); + if(args[3].l) + t.pEnv->DeleteLocalRef(static_cast<jintArray>(args[3].l)); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } + + return out ? new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection ) : nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Date.cxx b/connectivity/source/drivers/jdbc/Date.cxx new file mode 100644 index 000000000..8adaf455a --- /dev/null +++ b/connectivity/source/drivers/jdbc/Date.cxx @@ -0,0 +1,41 @@ +/* -*- 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 <java/util/Date.hxx> + +using namespace connectivity; + +//************ Class: java.util.Date + + +jclass java_util_Date::theClass = nullptr; + +java_util_Date::~java_util_Date() +{} + +jclass java_util_Date::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/util/Date"); + return theClass; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/DriverPropertyInfo.cxx b/connectivity/source/drivers/jdbc/DriverPropertyInfo.cxx new file mode 100644 index 000000000..9c33eeb60 --- /dev/null +++ b/connectivity/source/drivers/jdbc/DriverPropertyInfo.cxx @@ -0,0 +1,44 @@ +/* -*- 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 <java/sql/DriverPropertyInfo.hxx> + +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + + +//************ Class: java.sql.Driver + + +jclass java_sql_DriverPropertyInfo::theClass = nullptr; + +java_sql_DriverPropertyInfo::~java_sql_DriverPropertyInfo() +{} + +jclass java_sql_DriverPropertyInfo::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/DriverPropertyInfo"); + return theClass; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Exception.cxx b/connectivity/source/drivers/jdbc/Exception.cxx new file mode 100644 index 000000000..2fdef4ee8 --- /dev/null +++ b/connectivity/source/drivers/jdbc/Exception.cxx @@ -0,0 +1,39 @@ +/* -*- 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 <java/lang/Exception.hxx> +using namespace connectivity; + +//************ Class: java.lang.Exception + + +jclass java_lang_Exception::theClass = nullptr; + +java_lang_Exception::~java_lang_Exception() +{} + +jclass java_lang_Exception::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/lang/Exception"); + return theClass; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/InputStream.cxx b/connectivity/source/drivers/jdbc/InputStream.cxx new file mode 100644 index 000000000..c384760b3 --- /dev/null +++ b/connectivity/source/drivers/jdbc/InputStream.cxx @@ -0,0 +1,113 @@ +/* -*- 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 <com/sun/star/io/BufferSizeExceededException.hpp> +#include <java/io/InputStream.hxx> +#include <osl/diagnose.h> + +#include <string.h> + +using namespace connectivity; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + + +//************ Class: java.io.InputStream + + +jclass java_io_InputStream::theClass = nullptr; +java_io_InputStream::java_io_InputStream( JNIEnv * pEnv, jobject myObj ) + : java_lang_Object( pEnv, myObj ) +{ + SDBThreadAttach::addRef(); +} +java_io_InputStream::~java_io_InputStream() +{ + SDBThreadAttach::releaseRef(); +} + +jclass java_io_InputStream::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/io/InputStream"); + return theClass; +} + + +sal_Int32 SAL_CALL java_io_InputStream::readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) +{ + return readBytes(aData,nMaxBytesToRead); +} + +void SAL_CALL java_io_InputStream::skipBytes( sal_Int32 nBytesToSkip ) +{ + static jmethodID mID(nullptr); + callIntMethodWithIntArg_ThrowRuntime("skip",mID,nBytesToSkip); +} + +sal_Int32 SAL_CALL java_io_InputStream::available( ) +{ + static jmethodID mID(nullptr); + return callIntMethod_ThrowRuntime("available", mID); +} + +void SAL_CALL java_io_InputStream::closeInput( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowRuntime("close",mID); +} + +sal_Int32 SAL_CALL java_io_InputStream::readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) +{ + if (nBytesToRead < 0) + throw css::io::BufferSizeExceededException( THROW_WHERE, *this ); + + jint out(0); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + jbyteArray pByteArray = t.pEnv->NewByteArray(nBytesToRead); + static const char * const cSignature = "([BII)I"; + static const char * const cMethodName = "read"; + // execute Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwRuntime(t.pEnv, cMethodName,cSignature, mID); + out = t.pEnv->CallIntMethod( object, mID, pByteArray, 0, nBytesToRead ); + if ( !out ) + ThrowRuntimeException(t.pEnv,*this); + if(out > 0) + { + jboolean p = false; + aData.realloc ( out ); + memcpy(aData.getArray(),t.pEnv->GetByteArrayElements(pByteArray,&p),out); + } + t.pEnv->DeleteLocalRef(pByteArray); + } //t.pEnv + return out; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/JBigDecimal.cxx b/connectivity/source/drivers/jdbc/JBigDecimal.cxx new file mode 100644 index 000000000..7cbcd6486 --- /dev/null +++ b/connectivity/source/drivers/jdbc/JBigDecimal.cxx @@ -0,0 +1,79 @@ +/* -*- 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 <java/math/BigDecimal.hxx> +#include <java/tools.hxx> +using namespace connectivity; + +//************ Class: java.lang.Boolean + + +jclass java_math_BigDecimal::theClass = nullptr; + +java_math_BigDecimal::~java_math_BigDecimal() +{} + +jclass java_math_BigDecimal::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/math/BigDecimal"); + return theClass; +} + +java_math_BigDecimal::java_math_BigDecimal( const OUString& _par0 ): java_lang_Object( nullptr, nullptr ) +{ + SDBThreadAttach t; + if( !t.pEnv ) + return; + // Java-Call for the Constructor + // initialize temporary Variable + static const char * const cSignature = "(Ljava/lang/String;)V"; + jobject tempObj; + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, "<init>",cSignature, mID); + + jstring str = convertwchar_tToJavaString(t.pEnv,_par0.replace(',','.')); + tempObj = t.pEnv->NewObject( getMyClass(), mID, str ); + t.pEnv->DeleteLocalRef(str); + saveRef( t.pEnv, tempObj ); + t.pEnv->DeleteLocalRef( tempObj ); + ThrowSQLException( t.pEnv, nullptr ); + // and cleanup +} + +java_math_BigDecimal::java_math_BigDecimal( const double& _par0 ): java_lang_Object( nullptr, nullptr ) +{ + SDBThreadAttach t; + if( !t.pEnv ) + return; + // Java-Call for the Constructor + // initialize temporary Variable + static const char * const cSignature = "(D)V"; + jobject tempObj; + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, "<init>",cSignature, mID); + tempObj = t.pEnv->NewObject( getMyClass(), mID, _par0 ); + saveRef( t.pEnv, tempObj ); + t.pEnv->DeleteLocalRef( tempObj ); + ThrowSQLException( t.pEnv, nullptr ); + // and cleanup +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/JConnection.cxx b/connectivity/source/drivers/jdbc/JConnection.cxx new file mode 100644 index 000000000..1d33f2941 --- /dev/null +++ b/connectivity/source/drivers/jdbc/JConnection.cxx @@ -0,0 +1,804 @@ +/* -*- 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 <java/sql/Connection.hxx> +#include <java/lang/Class.hxx> +#include <java/tools.hxx> +#include <java/ContextClassLoader.hxx> +#include <java/sql/DatabaseMetaData.hxx> +#include <java/sql/JStatement.hxx> +#include <java/sql/Driver.hxx> +#include <java/sql/PreparedStatement.hxx> +#include <java/sql/CallableStatement.hxx> +#include <java/sql/SQLWarning.hxx> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <connectivity/dbexception.hxx> +#include <java/util/Property.hxx> +#include <java/LocalRef.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <jvmaccess/classpath.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <jni.h> +#include <strings.hrc> +#include <unotools/confignode.hxx> +#include <strings.hxx> + +#include <vector> +#include <memory> + +using namespace connectivity; +using namespace connectivity::jdbc; +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; + +namespace { + +struct ClassMapEntry { + ClassMapEntry( + OUString const & theClassPath, OUString const & theClassName): + classPath(theClassPath), className(theClassName), classLoader(nullptr), + classObject(nullptr) {} + + OUString classPath; + OUString className; + jweak classLoader; + jweak classObject; +}; + +typedef std::vector< ClassMapEntry > ClassMap; + +struct ClassMapData { + osl::Mutex mutex; + + ClassMap map; +}; + +template < typename T > +bool getLocalFromWeakRef( jweak& _weak, LocalRef< T >& _inout_local ) +{ + _inout_local.set( static_cast< T >( _inout_local.env().NewLocalRef( _weak ) ) ); + + if ( !_inout_local.is() ) + { + if ( _inout_local.env().ExceptionCheck()) + { + return false; + } + else if ( _weak != nullptr ) + { + _inout_local.env().DeleteWeakGlobalRef( _weak ); + _weak = nullptr; + } + } + return true; +} + +// Load a class. A map from pairs of (classPath, name) to pairs of weak Java +// references to (ClassLoader, Class) is maintained, so that a class is only +// loaded once. +// +// It may happen that the weak reference to the ClassLoader becomes null while +// the reference to the Class remains non-null (in case the Class was actually +// loaded by some parent of the ClassLoader), in which case the ClassLoader is +// resurrected (which cannot cause any classes to be loaded multiple times, as +// the ClassLoader is no longer reachable, so no classes it has ever loaded are +// still reachable). +// +// Similarly, it may happen that the weak reference to the Class becomes null +// while the reference to the ClassLoader remains non-null, in which case the +// Class is simply re-loaded. +// +// This code is close to the implementation of jvmaccess::ClassPath::loadClass +// in jvmaccess/classpath.hxx, but not close enough to avoid the duplication. +// +// If false is returned, a (still pending) JNI exception occurred. +bool loadClass( + Reference< XComponentContext > const & context, JNIEnv& environment, + OUString const & classPath, OUString const & name, + LocalRef< jobject > * classLoaderPtr, LocalRef< jclass > * classPtr) +{ + OSL_ASSERT(classLoaderPtr != nullptr); + // For any jweak entries still present in the map upon destruction, + // DeleteWeakGlobalRef is not called (which is a leak): + static ClassMapData classMapData; + osl::MutexGuard g(classMapData.mutex); + ClassMap::iterator i(classMapData.map.begin()); + LocalRef< jobject > cloader(environment); + LocalRef< jclass > cl(environment); + // Prune dangling weak references from the list while searching for a match, + // so that the list cannot grow unbounded: + for (; i != classMapData.map.end();) + { + LocalRef< jobject > classLoader( environment ); + if ( !getLocalFromWeakRef( i->classLoader, classLoader ) ) + return false; + + LocalRef< jclass > classObject( environment ); + if ( !getLocalFromWeakRef( i->classObject, classObject ) ) + return false; + + if ( !classLoader.is() && !classObject.is() ) + { + i = classMapData.map.erase(i); + } + else if ( i->classPath == classPath && i->className == name ) + { + cloader.set( classLoader.release() ); + cl.set( classObject.release() ); + break; + } + else + { + ++i; + } + } + if ( !cloader.is() || !cl.is() ) + { + if ( i == classMapData.map.end() ) + { + // Push a new ClassMapEntry (which can potentially fail) before + // loading the class, so that it never happens that a class is + // loaded but not added to the map (which could have effects on the + // JVM that are not easily undone). If the pushed ClassMapEntry is + // not used after all (return false, etc.) it will be pruned on next + // call because its classLoader/classObject are null: + classMapData.map.push_back( ClassMapEntry( classPath, name ) ); + i = std::prev(classMapData.map.end()); + } + + LocalRef< jclass > clClass( environment ); + clClass.set( environment.FindClass( "java/net/URLClassLoader" ) ); + if ( !clClass.is() ) + return false; + + jweak wcloader = nullptr; + if (!cloader.is()) + { + jmethodID ctorLoader( environment.GetMethodID( clClass.get(), "<init>", "([Ljava/net/URL;)V" ) ); + if (ctorLoader == nullptr) + return false; + + LocalRef< jobjectArray > arr( environment ); + arr.set( jvmaccess::ClassPath::translateToUrls( context, &environment, classPath ) ); + if ( !arr.is() ) + return false; + + jvalue arg; + arg.l = arr.get(); + cloader.set( environment.NewObjectA( clClass.get(), ctorLoader, &arg ) ); + if ( !cloader.is() ) + return false; + + wcloader = environment.NewWeakGlobalRef( cloader.get() ); + if ( wcloader == nullptr ) + return false; + } + + jweak wcl = nullptr; + if ( !cl.is() ) + { + jmethodID methLoadClass( environment.GetMethodID( clClass.get(), "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;" ) ); + if ( methLoadClass == nullptr ) + return false; + + LocalRef< jstring > str( environment ); + str.set( convertwchar_tToJavaString( &environment, name ) ); + if ( !str.is() ) + return false; + + jvalue arg; + arg.l = str.get(); + cl.set( static_cast< jclass >( environment.CallObjectMethodA( cloader.get(), methLoadClass, &arg ) ) ); + if ( !cl.is() ) + return false; + + wcl = environment.NewWeakGlobalRef( cl.get() ); + if ( wcl == nullptr ) + return false; + } + + if ( wcloader != nullptr) + { + i->classLoader = wcloader; + } + if ( wcl != nullptr ) + { + i->classObject = wcl; + } + } + + classLoaderPtr->set( cloader.release() ); + classPtr->set( cl.release() ); + return true; +} + +} + + +IMPLEMENT_SERVICE_INFO(java_sql_Connection,"com.sun.star.sdbcx.JConnection","com.sun.star.sdbc.Connection"); + + +//************ Class: java.sql.Connection + +jclass java_sql_Connection::theClass = nullptr; + +java_sql_Connection::java_sql_Connection( const java_sql_Driver& _rDriver ) + :java_lang_Object() + ,m_xContext( _rDriver.getContext() ) + ,m_pDriver( &_rDriver ) + ,m_pDriverobject(nullptr) + ,m_pDriverClassLoader() + ,m_Driver_theClass(nullptr) + ,m_aLogger( _rDriver.getLogger() ) + ,m_bIgnoreDriverPrivileges(true) + ,m_bIgnoreCurrency(false) +{ +} + +java_sql_Connection::~java_sql_Connection() +{ + ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(); + if ( !xTest.is() ) + return; + + SDBThreadAttach t; + clearObject(*t.pEnv); + + { + if ( m_pDriverobject ) + t.pEnv->DeleteGlobalRef( m_pDriverobject ); + m_pDriverobject = nullptr; + if ( m_Driver_theClass ) + t.pEnv->DeleteGlobalRef( m_Driver_theClass ); + m_Driver_theClass = nullptr; + } + SDBThreadAttach::releaseRef(); +} + +void java_sql_Connection::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + m_aLogger.log( LogLevel::INFO, STR_LOG_SHUTDOWN_CONNECTION ); + + java_sql_Connection_BASE::disposing(); + + if ( object ) + { + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("close", mID); + } +} + +jclass java_sql_Connection::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/Connection"); + return theClass; +} + + +OUString SAL_CALL java_sql_Connection::getCatalog( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + + static jmethodID mID(nullptr); + return callStringMethod("getCatalog",mID); +} + +Reference< XDatabaseMetaData > SAL_CALL java_sql_Connection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/DatabaseMetaData;", mID); + if(out) + { + xMetaData = new java_sql_DatabaseMetaData( t.pEnv, out, *this ); + m_xMetaData = xMetaData; + } + } + + return xMetaData; +} + +void SAL_CALL java_sql_Connection::close( ) +{ + dispose(); +} + +void SAL_CALL java_sql_Connection::commit( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("commit", mID); +} + +sal_Bool SAL_CALL java_sql_Connection::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + static jmethodID mID(nullptr); + return callBooleanMethod( "isClosed", mID ) && java_sql_Connection_BASE::rBHelper.bDisposed; +} + +sal_Bool SAL_CALL java_sql_Connection::isReadOnly( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + static jmethodID mID(nullptr); + return callBooleanMethod( "isReadOnly", mID ); +} + +void SAL_CALL java_sql_Connection::setCatalog( const OUString& catalog ) +{ + static jmethodID mID(nullptr); + callVoidMethodWithStringArg("setCatalog",mID,catalog); +} + +void SAL_CALL java_sql_Connection::rollback( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("rollback", mID); +} + +sal_Bool SAL_CALL java_sql_Connection::getAutoCommit( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "getAutoCommit", mID ); +} + +void SAL_CALL java_sql_Connection::setReadOnly( sal_Bool readOnly ) +{ + static jmethodID mID(nullptr); + callVoidMethodWithBoolArg_ThrowSQL("setReadOnly", mID, readOnly); +} + +void SAL_CALL java_sql_Connection::setAutoCommit( sal_Bool autoCommit ) +{ + static jmethodID mID(nullptr); + callVoidMethodWithBoolArg_ThrowSQL("setAutoCommit", mID, autoCommit); +} + +Reference< css::container::XNameAccess > SAL_CALL java_sql_Connection::getTypeMap( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + callObjectMethod(t.pEnv,"getTypeMap","()Ljava/util/Map;", mID); + // WARNING: the caller becomes the owner of the returned pointer + return nullptr; +} + +void SAL_CALL java_sql_Connection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this ); +} + + +sal_Int32 SAL_CALL java_sql_Connection::getTransactionIsolation( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + + static jmethodID mID(nullptr); + return callIntMethod_ThrowSQL("getTransactionIsolation", mID); +} + +void SAL_CALL java_sql_Connection::setTransactionIsolation( sal_Int32 level ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowSQL("setTransactionIsolation", mID, level); +} + +Reference< XStatement > SAL_CALL java_sql_Connection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_CREATE_STATEMENT ); + + SDBThreadAttach t; + java_sql_Statement* pStatement = new java_sql_Statement( t.pEnv, *this ); + Reference< XStatement > xStmt = pStatement; + m_aStatements.push_back( WeakReferenceHelper( xStmt ) ); + + m_aLogger.log( LogLevel::FINE, STR_LOG_CREATED_STATEMENT_ID, pStatement->getStatementObjectID() ); + return xStmt; +} + +Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_STATEMENT, sql ); + + SDBThreadAttach t; + + java_sql_PreparedStatement* pStatement = new java_sql_PreparedStatement( t.pEnv, *this, sql ); + Reference< XPreparedStatement > xReturn( pStatement ); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + + m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_STATEMENT_ID, pStatement->getStatementObjectID() ); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL java_sql_Connection::prepareCall( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARE_CALL, sql ); + + SDBThreadAttach t; + + java_sql_CallableStatement* pStatement = new java_sql_CallableStatement( t.pEnv, *this, sql ); + Reference< XPreparedStatement > xStmt( pStatement ); + m_aStatements.push_back(WeakReferenceHelper(xStmt)); + + m_aLogger.log( LogLevel::FINE, STR_LOG_PREPARED_CALL_ID, pStatement->getStatementObjectID() ); + return xStmt; +} + +OUString SAL_CALL java_sql_Connection::nativeSQL( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + + OUString aStr; + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + + // initialize temporary Variable + static const char * const cSignature = "(Ljava/lang/String;)Ljava/lang/String;"; + static const char * const cMethodName = "nativeSQL"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + // Convert Parameter + jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,sql)); + + jobject out = t.pEnv->CallObjectMethod( object, mID, str.get() ); + aStr = JavaString2String(t.pEnv, static_cast<jstring>(out) ); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } //t.pEnv + + m_aLogger.log( LogLevel::FINER, STR_LOG_NATIVE_SQL, sql, aStr ); + + return aStr; +} + +void SAL_CALL java_sql_Connection::clearWarnings( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("clearWarnings", mID); +} + +Any SAL_CALL java_sql_Connection::getWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Connection_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID); + // WARNING: the caller becomes the owner of the returned pointer + if( out ) + { + java_sql_SQLWarning_BASE warn_base(t.pEnv, out); + SQLException aAsException( java_sql_SQLWarning( warn_base, *this ) ); + + // translate to warning + SQLWarning aWarning; + aWarning.Context = aAsException.Context; + aWarning.Message = aAsException.Message; + aWarning.SQLState = aAsException.SQLState; + aWarning.ErrorCode = aAsException.ErrorCode; + aWarning.NextException = aAsException.NextException; + + return makeAny( aWarning ); + } + + return Any(); +} + + +namespace +{ + OUString lcl_getDriverLoadErrorMessage( const ::connectivity::SharedResources& _aResource,const OUString& _rDriverClass, const OUString& _rDriverClassPath ) + { + OUString sError1( _aResource.getResourceStringWithSubstitution( + STR_NO_CLASSNAME, + "$classname$", _rDriverClass + ) ); + if ( !_rDriverClassPath.isEmpty() ) + { + const OUString sError2( _aResource.getResourceStringWithSubstitution( + STR_NO_CLASSNAME_PATH, + "$classpath$", _rDriverClassPath + ) ); + sError1 += sError2; + } // if ( _rDriverClassPath.getLength() ) + return sError1; + } +} + + +namespace +{ + bool lcl_setSystemProperties_nothrow( const java::sql::ConnectionLog& _rLogger, + JNIEnv& _rEnv, const Sequence< NamedValue >& _rSystemProperties ) + { + if ( !_rSystemProperties.hasElements() ) + // nothing to do + return true; + + LocalRef< jclass > systemClass( _rEnv ); + jmethodID nSetPropertyMethodID = nullptr; + // retrieve the java.lang.System class + systemClass.set( _rEnv.FindClass( "java/lang/System" ) ); + if ( systemClass.is() ) + { + nSetPropertyMethodID = _rEnv.GetStaticMethodID( + systemClass.get(), "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" ); + } + + if ( nSetPropertyMethodID == nullptr ) + return false; + + for ( auto const & systemProp : _rSystemProperties ) + { + OUString sValue; + OSL_VERIFY( systemProp.Value >>= sValue ); + + _rLogger.log( LogLevel::FINER, STR_LOG_SETTING_SYSTEM_PROPERTY, systemProp.Name, sValue ); + + LocalRef< jstring > jName( _rEnv, convertwchar_tToJavaString( &_rEnv, systemProp.Name ) ); + LocalRef< jstring > jValue( _rEnv, convertwchar_tToJavaString( &_rEnv, sValue ) ); + + _rEnv.CallStaticObjectMethod( systemClass.get(), nSetPropertyMethodID, jName.get(), jValue.get() ); + LocalRef< jthrowable > throwable( _rEnv, _rEnv.ExceptionOccurred() ); + if ( throwable.is() ) + return false; + } + + return true; + } +} + + +void java_sql_Connection::loadDriverFromProperties( const OUString& _sDriverClass, const OUString& _sDriverClassPath, + const Sequence< NamedValue >& _rSystemProperties ) +{ + // first try if the jdbc driver is already registered at the driver manager + SDBThreadAttach t; + try + { + if ( !object ) + { + if ( !lcl_setSystemProperties_nothrow( getLogger(), *t.pEnv, _rSystemProperties ) ) + ThrowLoggedSQLException( getLogger(), t.pEnv, *this ); + + m_pDriverClassLoader.reset(); + + // here I try to find the class for jdbc driver + java_sql_SQLException_BASE::st_getMyClass(); + java_lang_Throwable::st_getMyClass(); + + if ( _sDriverClass.isEmpty() ) + { + m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_DRIVER_CLASS ); + ::dbtools::throwGenericSQLException( + lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ), + *this + ); + } + else + { + m_aLogger.log( LogLevel::INFO, STR_LOG_LOADING_DRIVER, _sDriverClass ); + // the driver manager holds the class of the driver for later use + std::unique_ptr< java_lang_Class > pDrvClass; + if ( _sDriverClassPath.isEmpty() ) + { + // if forName didn't find the class it will throw an exception + pDrvClass.reset(java_lang_Class::forName(_sDriverClass)); + } + else + { + LocalRef< jclass > driverClass(t.env()); + LocalRef< jobject > driverClassLoader(t.env()); + + loadClass( + m_pDriver->getContext(), + t.env(), _sDriverClassPath, _sDriverClass, &driverClassLoader, &driverClass ); + + m_pDriverClassLoader.set( driverClassLoader ); + pDrvClass.reset( new java_lang_Class( t.pEnv, driverClass.release() ) ); + + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + if (pDrvClass) + { + LocalRef< jobject > driverObject( t.env() ); + driverObject.set( pDrvClass->newInstanceObject() ); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + m_pDriverobject = driverObject.release(); + + if( m_pDriverobject ) + m_pDriverobject = t.pEnv->NewGlobalRef( m_pDriverobject ); + + { + jclass tempClass = t.pEnv->GetObjectClass(m_pDriverobject); + if ( m_pDriverobject ) + { + m_Driver_theClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass )); + t.pEnv->DeleteLocalRef( tempClass ); + } + } + } + m_aLogger.log( LogLevel::INFO, STR_LOG_CONN_SUCCESS ); + } + } + } + catch( const SQLException& ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw SQLException( + lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ), + *this, + OUString(), + 1000, + anyEx); + } + catch( Exception& ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + ::dbtools::throwGenericSQLException( + lcl_getDriverLoadErrorMessage( getResources(),_sDriverClass, _sDriverClassPath ), + *this, + anyEx + ); + } +} + +OUString java_sql_Connection::impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass) +{ + static const char s_sNodeName[] = "org.openoffice.Office.DataAccess/JDBC/DriverClassPaths"; + ::utl::OConfigurationTreeRoot aNamesRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext( + m_pDriver->getContext(), s_sNodeName, -1, ::utl::OConfigurationTreeRoot::CM_READONLY); + OUString sURL; + if ( aNamesRoot.isValid() && aNamesRoot.hasByName( _sDriverClass ) ) + { + ::utl::OConfigurationNode aRegisterObj = aNamesRoot.openNode( _sDriverClass ); + OSL_VERIFY( aRegisterObj.getNodeValue( "Path" ) >>= sURL ); + } + return sURL; +} + +bool java_sql_Connection::construct(const OUString& url, + const Sequence< PropertyValue >& info) +{ + { // initialize the java vm + ::rtl::Reference< jvmaccess::VirtualMachine > xTest = java_lang_Object::getVM(m_xContext); + if ( !xTest.is() ) + throwGenericSQLException(STR_NO_JAVA,*this); + } + SDBThreadAttach t; + SDBThreadAttach::addRef(); // will be released in dtor + if ( !t.pEnv ) + throwGenericSQLException(STR_NO_JAVA,*this); + + OUString sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values + bool bAutoRetrievingEnabled = false; // set to <TRUE/> when we should allow to query for generated values + OUString sDriverClassPath,sDriverClass; + Sequence< NamedValue > aSystemProperties; + + ::comphelper::NamedValueCollection aSettings( info ); + sDriverClass = aSettings.getOrDefault( "JavaDriverClass", sDriverClass ); + sDriverClassPath = aSettings.getOrDefault( "JavaDriverClassPath", sDriverClassPath); + if ( sDriverClassPath.isEmpty() ) + sDriverClassPath = impl_getJavaDriverClassPath_nothrow(sDriverClass); + bAutoRetrievingEnabled = aSettings.getOrDefault( "IsAutoRetrievingEnabled", bAutoRetrievingEnabled ); + sGeneratedValueStatement = aSettings.getOrDefault( "AutoRetrievingStatement", sGeneratedValueStatement ); + m_bIgnoreDriverPrivileges = aSettings.getOrDefault( "IgnoreDriverPrivileges", m_bIgnoreDriverPrivileges ); + m_bIgnoreCurrency = aSettings.getOrDefault( "IgnoreCurrency", m_bIgnoreCurrency ); + aSystemProperties = aSettings.getOrDefault( "SystemProperties", aSystemProperties ); + m_aCatalogRestriction = aSettings.getOrDefault( "ImplicitCatalogRestriction", Any() ); + m_aSchemaRestriction = aSettings.getOrDefault( "ImplicitSchemaRestriction", Any() ); + + loadDriverFromProperties( sDriverClass, sDriverClassPath, aSystemProperties ); + + enableAutoRetrievingEnabled(bAutoRetrievingEnabled); + setAutoRetrievingStatement(sGeneratedValueStatement); + + if ( t.pEnv && m_Driver_theClass && m_pDriverobject ) + { + // Java-Call + static const char * const cSignature = "(Ljava/lang/String;Ljava/util/Properties;)Ljava/sql/Connection;"; + static const char * const cMethodName = "connect"; + jmethodID mID = t.pEnv->GetMethodID( m_Driver_theClass, cMethodName, cSignature ); + + if ( mID ) + { + jvalue args[2]; + // convert Parameter + args[0].l = convertwchar_tToJavaString(t.pEnv,url); + std::unique_ptr<java_util_Properties> pProps = createStringPropertyArray(info); + args[1].l = pProps->getJavaObject(); + + LocalRef< jobject > ensureDelete( t.env(), args[0].l ); + + jobject out = nullptr; + // In some cases (e.g., + // connectivity/source/drivers/hsqldb/HDriver.cxx:1.24 + // l. 249) the JavaDriverClassPath contains multiple jars, + // as creating the JavaDriverClass instance requires + // (reflective) access to those other jars. Now, if the + // JavaDriverClass is actually loaded by some parent class + // loader (e.g., because its jar is also on the global + // class path), it would still not have access to the + // additional jars on the JavaDriverClassPath. Hence, the + // JavaDriverClassPath class loader is pushed as context + // class loader around the JavaDriverClass instance + // creation: + // #i82222# / 2007-10-15 + { + ContextClassLoaderScope ccl( t.env(), getDriverClassLoader(), getLogger(), *this ); + out = t.pEnv->CallObjectMethod( m_pDriverobject, mID, args[0].l,args[1].l ); + pProps.reset(); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + + if ( !out ) + m_aLogger.log( LogLevel::SEVERE, STR_LOG_NO_SYSTEM_CONNECTION ); + + if ( out ) + object = t.pEnv->NewGlobalRef( out ); + + if ( object ) + m_aLogger.log( LogLevel::INFO, STR_LOG_GOT_JDBC_CONNECTION, url ); + + m_aConnectionInfo = info; + } //mID + } //t.pEnv + return object != nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/JDriver.cxx b/connectivity/source/drivers/jdbc/JDriver.cxx new file mode 100644 index 000000000..3ec181bb3 --- /dev/null +++ b/connectivity/source/drivers/jdbc/JDriver.cxx @@ -0,0 +1,246 @@ +/* -*- 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 <java/sql/Driver.hxx> +#include <java/sql/Connection.hxx> +#include <sal/log.hxx> +#include <connectivity/dbexception.hxx> +#include <jvmfwk/framework.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <strings.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; + + +java_sql_Driver::java_sql_Driver(const Reference< css::uno::XComponentContext >& _rxContext) + :m_aContext( _rxContext ) + ,m_aLogger( _rxContext, "org.openoffice.sdbc.jdbcBridge" ) +{ +} + +java_sql_Driver::~java_sql_Driver() +{ +} + +// static ServiceInfo + +OUString java_sql_Driver::getImplementationName_Static( ) +{ + return "com.sun.star.comp.sdbc.JDBCDriver"; + // this name is referenced in the configuration and in the jdbc.xml + // Please take care when changing it. +} + +Sequence< OUString > java_sql_Driver::getSupportedServiceNames_Static( ) +{ + Sequence<OUString> aSNS { "com.sun.star.sdbc.Driver" }; + return aSNS; +} + +css::uno::Reference< css::uno::XInterface > connectivity::java_sql_Driver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory) +{ + return *(new java_sql_Driver( comphelper::getComponentContext(_rxFactory))); +} + +OUString SAL_CALL java_sql_Driver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL java_sql_Driver::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +Sequence< OUString > SAL_CALL java_sql_Driver::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + +Reference< XConnection > SAL_CALL java_sql_Driver::connect( const OUString& url, const + Sequence< PropertyValue >& info ) +{ + m_aLogger.log( LogLevel::INFO, STR_LOG_DRIVER_CONNECTING_URL, url ); + + Reference< XConnection > xOut; + if ( acceptsURL(url ) ) + { + java_sql_Connection* pConnection = new java_sql_Connection( *this ); + xOut = pConnection; + if ( !pConnection->construct(url,info) ) + xOut.clear(); // an error occurred and the java driver didn't throw an exception + else + m_aLogger.log( LogLevel::INFO, STR_LOG_DRIVER_SUCCESS ); + } + return xOut; +} + +sal_Bool SAL_CALL java_sql_Driver::acceptsURL( const OUString& url ) +{ + // don't ask the real driver for the url + // I feel responsible for all jdbc url's + bool bEnabled = false; + javaFrameworkError e = jfw_getEnabled(&bEnabled); + switch (e) { + case JFW_E_NONE: + break; + case JFW_E_DIRECT_MODE: + SAL_INFO( + "connectivity.jdbc", + "jfw_getEnabled: JFW_E_DIRECT_MODE, assuming true"); + bEnabled = true; + break; + default: + SAL_WARN("connectivity.jdbc", "jfw_getEnabled: error code " << +e); + break; + } + return bEnabled && url.startsWith("jdbc:"); +} + +Sequence< DriverPropertyInfo > SAL_CALL java_sql_Driver::getPropertyInfo( const OUString& url, + const Sequence< PropertyValue >& /*info*/ ) +{ + if ( acceptsURL(url) ) + { + std::vector< DriverPropertyInfo > aDriverInfo; + + Sequence< OUString > aBooleanValues(2); + aBooleanValues[0] = "false"; + aBooleanValues[1] = "true"; + + aDriverInfo.push_back(DriverPropertyInfo( + "JavaDriverClass" + ,"The JDBC driver class name." + ,true + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "JavaDriverClassPath" + ,"The class path where to look for the JDBC driver." + ,true + , "" + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "SystemProperties" + ,"Additional properties to set at java.lang.System before loading the driver." + ,true + , "" + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "ParameterNameSubstitution" + ,"Change named parameters with '?'." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "IgnoreDriverPrivileges" + ,"Ignore the privileges from the database driver." + ,false + , "false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "IsAutoRetrievingEnabled" + ,"Retrieve generated values." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "AutoRetrievingStatement" + ,"Auto-increment statement." + ,false + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "GenerateASBeforeCorrelationName" + ,"Generate AS before table correlation names." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "IgnoreCurrency" + ,"Ignore the currency field from the ResultsetMetaData." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "EscapeDateTime" + ,"Escape date time format." + ,false + ,"true" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "TypeInfoSettings" + ,"Defines how the type info of the database metadata should be manipulated." + ,false + ,OUString( ) + ,Sequence< OUString > ()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "ImplicitCatalogRestriction" + ,"The catalog which should be used in getTables calls, when the caller passed NULL." + ,false + ,OUString( ) + ,Sequence< OUString > ()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "ImplicitSchemaRestriction" + ,"The schema which should be used in getTables calls, when the caller passed NULL." + ,false + ,OUString( ) + ,Sequence< OUString > ()) + ); + return Sequence< DriverPropertyInfo >(aDriverInfo.data(),aDriverInfo.size()); + } + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + return Sequence< DriverPropertyInfo >(); +} + +sal_Int32 SAL_CALL java_sql_Driver::getMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL java_sql_Driver::getMinorVersion( ) +{ + return 0; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/JStatement.cxx b/connectivity/source/drivers/jdbc/JStatement.cxx new file mode 100644 index 000000000..9bfe11838 --- /dev/null +++ b/connectivity/source/drivers/jdbc/JStatement.cxx @@ -0,0 +1,823 @@ +/* -*- 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 <java/sql/JStatement.hxx> +#include <java/sql/ResultSet.hxx> +#include <java/sql/Connection.hxx> +#include <java/sql/SQLWarning.hxx> +#include <java/tools.hxx> +#include <java/ContextClassLoader.hxx> +#include <comphelper/property.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/sequence.hxx> +#include <TConnection.hxx> +#include <comphelper/types.hxx> +#include <tools/diagnose_ex.h> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> + +#include <strings.hxx> + +#include <algorithm> +#include <string.h> + +using namespace ::comphelper; +using namespace connectivity; +using namespace ::cppu; + +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; + + +//************ Class: java.sql.Statement + + +jclass java_sql_Statement_Base::theClass = nullptr; + + +java_sql_Statement_Base::java_sql_Statement_Base( JNIEnv * pEnv, java_sql_Connection& _rCon ) + :java_sql_Statement_BASE(m_aMutex) + ,java_lang_Object( pEnv, nullptr ) + ,OPropertySetHelper(java_sql_Statement_BASE::rBHelper) + ,m_pConnection( &_rCon ) + ,m_aLogger( _rCon.getLogger(), java::sql::ConnectionLog::STATEMENT ) + ,m_nResultSetConcurrency(ResultSetConcurrency::READ_ONLY) + ,m_nResultSetType(ResultSetType::FORWARD_ONLY) + ,m_bEscapeProcessing(true) +{ +} + + +java_sql_Statement_Base::~java_sql_Statement_Base() +{ +} + + +void SAL_CALL OStatement_BASE2::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + if ( object ) + { + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("close", mID); + } + + ::comphelper::disposeComponent(m_xGeneratedStatement); + m_pConnection.clear(); + + java_sql_Statement_Base::disposing(); +} + +jclass java_sql_Statement_Base::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/Statement"); + return theClass; +} + +void SAL_CALL java_sql_Statement_Base::disposing() +{ + m_aLogger.log( LogLevel::FINE, STR_LOG_CLOSING_STATEMENT ); + java_sql_Statement_BASE::disposing(); + clearObject(); +} + + +Any SAL_CALL java_sql_Statement_Base::queryInterface( const Type & rType ) +{ + if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() && rType == cppu::UnoType<XGeneratedResultSet>::get()) + return Any(); + Any aRet( java_sql_Statement_BASE::queryInterface(rType) ); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + +Sequence< Type > SAL_CALL java_sql_Statement_Base::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(), + cppu::UnoType<css::beans::XFastPropertySet>::get(), + cppu::UnoType<css::beans::XPropertySet>::get()); + + Sequence< Type > aOldTypes = java_sql_Statement_BASE::getTypes(); + if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() ) + { + auto newEnd = std::remove(aOldTypes.begin(), aOldTypes.end(), + cppu::UnoType<XGeneratedResultSet>::get()); + aOldTypes.realloc(std::distance(aOldTypes.begin(), newEnd)); + } + + return ::comphelper::concatSequences(aTypes.getTypes(),aOldTypes); +} + +Reference< XResultSet > SAL_CALL java_sql_Statement_Base::getGeneratedValues( ) +{ + m_aLogger.log( LogLevel::FINE, STR_LOG_GENERATED_VALUES ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + jobject out(nullptr); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + // initialize temporary Variable + try + { + static jmethodID mID(nullptr); + out = callResultSetMethod(t.env(),"getGeneratedKeys",mID); + } + catch(const SQLException&) + { + // ignore + } + + Reference< XResultSet > xRes; + if ( !out ) + { + OSL_ENSURE( m_pConnection.is() && m_pConnection->isAutoRetrievingEnabled(),"Illegal call here. isAutoRetrievingEnabled is false!"); + if ( m_pConnection.is() ) + { + OUString sStmt = m_pConnection->getTransformedGeneratedStatement(m_sSqlStatement); + if ( !sStmt.isEmpty() ) + { + m_aLogger.log( LogLevel::FINER, STR_LOG_GENERATED_VALUES_FALLBACK, sStmt ); + ::comphelper::disposeComponent(m_xGeneratedStatement); + m_xGeneratedStatement = m_pConnection->createStatement(); + xRes = m_xGeneratedStatement->executeQuery(sStmt); + } + } + } + else + xRes = new java_sql_ResultSet( t.pEnv, out, m_aLogger,*m_pConnection, this ); + return xRes; +} + + +void SAL_CALL java_sql_Statement_Base::cancel( ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowRuntime("cancel",mID); +} + + +void SAL_CALL java_sql_Statement_Base::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (java_sql_Statement_BASE::rBHelper.bDisposed) + throw DisposedException(); + } + dispose(); +} + + +void SAL_CALL java_sql_Statement::clearBatch( ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("clearBatch", mID); + } //t.pEnv +} + + +sal_Bool SAL_CALL java_sql_Statement_Base::execute( const OUString& sql ) +{ + m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTE_STATEMENT, sql ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + bool out(false); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + createStatement(t.pEnv); + m_sSqlStatement = sql; + // initialize temporary Variable + static const char * const cSignature = "(Ljava/lang/String;)Z"; + static const char * const cMethodName = "execute"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + // convert Parameter + jdbc::LocalRef< jstring > str( t.env(), convertwchar_tToJavaString( t.pEnv, sql ) ); + { + jdbc::ContextClassLoaderScope ccl( t.env(), + m_pConnection.is() ? m_pConnection->getDriverClassLoader() : jdbc::GlobalRef< jobject >(), + m_aLogger, + *this + ); + + out = t.pEnv->CallBooleanMethod( object, mID, str.get() ); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } //t.pEnv + return out; +} + + +Reference< XResultSet > SAL_CALL java_sql_Statement_Base::executeQuery( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTE_QUERY, sql ); + + jobject out(nullptr); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + createStatement(t.pEnv); + m_sSqlStatement = sql; + // initialize temporary variable + static const char * const cSignature = "(Ljava/lang/String;)Ljava/sql/ResultSet;"; + static const char * const cMethodName = "executeQuery"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + // convert Parameter + jdbc::LocalRef< jstring > str( t.env(), convertwchar_tToJavaString( t.pEnv, sql ) ); + { + jdbc::ContextClassLoaderScope ccl( t.env(), + m_pConnection.is() ? m_pConnection->getDriverClassLoader() : jdbc::GlobalRef< jobject >(), + m_aLogger, + *this + ); + + out = t.pEnv->CallObjectMethod( object, mID, str.get() ); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } //t.pEnv + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_ResultSet( t.pEnv, out, m_aLogger, *m_pConnection,this ); +} + +Reference< XConnection > SAL_CALL java_sql_Statement_Base::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + return Reference< XConnection >(m_pConnection.get()); +} + + +Any SAL_CALL java_sql_Statement::queryInterface( const Type & rType ) +{ + Any aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this)); + return aRet.hasValue() ? aRet : java_sql_Statement_Base::queryInterface(rType); +} + + +void SAL_CALL java_sql_Statement::addBatch( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethodWithStringArg("addBatch",mID,sql); + } //t.pEnv +} + + +Sequence< sal_Int32 > SAL_CALL java_sql_Statement::executeBatch( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + Sequence< sal_Int32 > aSeq; + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jintArray out = static_cast<jintArray>(callObjectMethod(t.pEnv,"executeBatch","()[I", mID)); + if (out) + { + jboolean p = false; + aSeq.realloc(t.pEnv->GetArrayLength(out)); + memcpy(aSeq.getArray(),t.pEnv->GetIntArrayElements(out,&p),aSeq.getLength()); + t.pEnv->DeleteLocalRef(out); + } + return aSeq; +} + + +sal_Int32 SAL_CALL java_sql_Statement_Base::executeUpdate( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTE_UPDATE, sql ); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + m_sSqlStatement = sql; + static jmethodID mID(nullptr); + return callIntMethodWithStringArg("executeUpdate",mID,sql); +} + + +Reference< css::sdbc::XResultSet > SAL_CALL java_sql_Statement_Base::getResultSet( ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callResultSetMethod(t.env(),"getResultSet",mID); + + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_ResultSet( t.pEnv, out, m_aLogger, *m_pConnection,this ); +} + + +sal_Int32 SAL_CALL java_sql_Statement_Base::getUpdateCount( ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + sal_Int32 out = callIntMethod_ThrowSQL("getUpdateCount", mID); + m_aLogger.log( LogLevel::FINER, STR_LOG_UPDATE_COUNT, out ); + return out; +} + + +sal_Bool SAL_CALL java_sql_Statement_Base::getMoreResults( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "getMoreResults", mID ); +} + + +Any SAL_CALL java_sql_Statement_Base::getWarnings( ) +{ + SDBThreadAttach t; + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID); + // WARNING: the caller becomes the owner of the returned pointer + if( out ) + { + java_sql_SQLWarning_BASE warn_base( t.pEnv, out ); + return makeAny( + static_cast< css::sdbc::SQLException >( + java_sql_SQLWarning(warn_base,*static_cast<cppu::OWeakObject*>(this)))); + } + + return Any(); +} + +void SAL_CALL java_sql_Statement_Base::clearWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; + + { + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("clearWarnings", mID); + } +} + +sal_Int32 java_sql_Statement_Base::getQueryTimeOut() +{ + static jmethodID mID(nullptr); + return impl_getProperty("getQueryTimeOut",mID); +} + +sal_Int32 java_sql_Statement_Base::getMaxRows() +{ + static jmethodID mID(nullptr); + return impl_getProperty("getMaxRows",mID); +} + +sal_Int32 java_sql_Statement_Base::getResultSetConcurrency() +{ + static jmethodID mID(nullptr); + return impl_getProperty("getResultSetConcurrency",mID,m_nResultSetConcurrency); +} + + +sal_Int32 java_sql_Statement_Base::getResultSetType() +{ + static jmethodID mID(nullptr); + return impl_getProperty("getResultSetType",mID,m_nResultSetType); +} + +sal_Int32 java_sql_Statement_Base::impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nDefault) +{ + sal_Int32 out = _nDefault; + if ( object ) + out = callIntMethod_ThrowRuntime(_pMethodName, _inout_MethodID); + return out; +} + +sal_Int32 java_sql_Statement_Base::impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + return callIntMethod_ThrowRuntime(_pMethodName, _inout_MethodID); +} + +sal_Int32 java_sql_Statement_Base::getFetchDirection() +{ + static jmethodID mID(nullptr); + return impl_getProperty("getFetchDirection",mID); +} + +sal_Int32 java_sql_Statement_Base::getFetchSize() +{ + static jmethodID mID(nullptr); + return impl_getProperty("getFetchSize",mID); +} + +sal_Int32 java_sql_Statement_Base::getMaxFieldSize() +{ + static jmethodID mID(nullptr); + return impl_getProperty("getMaxFieldSize",mID); +} + +OUString java_sql_Statement_Base::getCursorName() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + try + { + return callStringMethod("getCursorName",mID); + } + catch(const SQLException&) + { + } + return OUString(); +} + +void java_sql_Statement_Base::setQueryTimeOut(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowRuntime("setQueryTimeOut", mID, _par0); +} + + +void java_sql_Statement_Base::setEscapeProcessing(bool _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_SET_ESCAPE_PROCESSING, _par0 ); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + m_bEscapeProcessing = _par0; + createStatement( t.pEnv ); + static jmethodID mID(nullptr); + callVoidMethodWithBoolArg_ThrowRuntime("setEscapeProcessing", mID, _par0); +} + +void java_sql_Statement_Base::setMaxRows(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowRuntime("setMaxRows", mID, _par0); +} + +void java_sql_Statement_Base::setResultSetConcurrency(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_RESULT_SET_CONCURRENCY, _par0 ); + m_nResultSetConcurrency = _par0; + + clearObject(); +} + +void java_sql_Statement_Base::setResultSetType(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_RESULT_SET_TYPE, _par0 ); + m_nResultSetType = _par0; + + clearObject(); +} + +void java_sql_Statement_Base::setFetchDirection(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINER, STR_LOG_FETCH_DIRECTION, _par0 ); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowRuntime("setFetchDirection", mID, _par0); +} + +void java_sql_Statement_Base::setFetchSize(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINER, STR_LOG_FETCH_SIZE, _par0 ); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowRuntime("setFetchSize", mID, _par0); +} + +void java_sql_Statement_Base::setMaxFieldSize(sal_Int32 _par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowRuntime("setMaxFieldSize", mID, _par0); +} + +void java_sql_Statement_Base::setCursorName(const OUString &_par0) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethodWithStringArg("setCursorName",mID,_par0); + } //t.pEnv +} + + +::cppu::IPropertyArrayHelper* java_sql_Statement_Base::createArrayHelper( ) const +{ + Sequence< Property > aProps(10); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + + +::cppu::IPropertyArrayHelper & java_sql_Statement_Base::getInfoHelper() + +{ + return *getArrayHelper(); +} + +sal_Bool java_sql_Statement_Base::convertFastPropertyValue( + Any & rConvertedValue, + Any & rOldValue, + sal_Int32 nHandle, + const Any& rValue ) +{ + try + { + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getQueryTimeOut()); + case PROPERTY_ID_MAXFIELDSIZE: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxFieldSize()); + case PROPERTY_ID_MAXROWS: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxRows()); + case PROPERTY_ID_CURSORNAME: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getCursorName()); + case PROPERTY_ID_RESULTSETCONCURRENCY: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetConcurrency()); + case PROPERTY_ID_RESULTSETTYPE: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetType()); + case PROPERTY_ID_FETCHDIRECTION: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection()); + case PROPERTY_ID_FETCHSIZE: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize()); + case PROPERTY_ID_ESCAPEPROCESSING: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bEscapeProcessing ); + case PROPERTY_ID_USEBOOKMARKS: + // return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAsLink); + default: + ; + } + } + catch(const css::lang::IllegalArgumentException&) + { + throw; + } + catch(const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("connectivity.jdbc"); + } + return false; +} + +void java_sql_Statement_Base::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const Any& rValue + ) +{ + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + setQueryTimeOut(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_MAXFIELDSIZE: + setMaxFieldSize(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_MAXROWS: + setMaxRows(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_CURSORNAME: + setCursorName(comphelper::getString(rValue)); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + setResultSetConcurrency(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_RESULTSETTYPE: + setResultSetType(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHDIRECTION: + setFetchDirection(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHSIZE: + setFetchSize(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_ESCAPEPROCESSING: + setEscapeProcessing( ::comphelper::getBOOL( rValue ) ); + break; + case PROPERTY_ID_USEBOOKMARKS: + // return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bAsLink); + default: + ; + } +} + +void java_sql_Statement_Base::getFastPropertyValue( + Any& rValue, + sal_Int32 nHandle + ) const +{ + java_sql_Statement_Base* THIS = const_cast<java_sql_Statement_Base*>(this); + try + { + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + rValue <<= THIS->getQueryTimeOut(); + break; + case PROPERTY_ID_MAXFIELDSIZE: + rValue <<= THIS->getMaxFieldSize(); + break; + case PROPERTY_ID_MAXROWS: + rValue <<= THIS->getMaxRows(); + break; + case PROPERTY_ID_CURSORNAME: + rValue <<= THIS->getCursorName(); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= THIS->getResultSetConcurrency(); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= THIS->getResultSetType(); + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= THIS->getFetchDirection(); + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= THIS->getFetchSize(); + break; + case PROPERTY_ID_ESCAPEPROCESSING: + rValue <<= m_bEscapeProcessing; + break; + case PROPERTY_ID_USEBOOKMARKS: + default: + ; + } + } + catch(const Exception&) + { + } +} + +jclass java_sql_Statement::theClass = nullptr; + +java_sql_Statement::~java_sql_Statement() +{} + +jclass java_sql_Statement::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/Statement"); + return theClass; +} + + +void java_sql_Statement::createStatement(JNIEnv* _pEnv) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + if( !(_pEnv && !object) ) + return; + + // initialize temporary variable + static const char * const cMethodName = "createStatement"; + // Java-Call + jobject out = nullptr; + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(II)Ljava/sql/Statement;"; + mID = _pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature ); + } + if( mID ){ + out = _pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID,m_nResultSetType,m_nResultSetConcurrency ); + } //mID + else + { + static const char * const cSignature2 = "()Ljava/sql/Statement;"; + static jmethodID mID2 = _pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature2 );OSL_ENSURE(mID2,"Unknown method id!"); + if( mID2 ){ + out = _pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID2); + } //mID + } + ThrowLoggedSQLException( m_aLogger, _pEnv, *this ); + + if ( out ) + object = _pEnv->NewGlobalRef( out ); +} + + +IMPLEMENT_SERVICE_INFO(java_sql_Statement,"com.sun.star.sdbcx.JStatement","com.sun.star.sdbc.Statement"); + +void SAL_CALL java_sql_Statement_Base::acquire() throw() +{ + java_sql_Statement_BASE::acquire(); +} + +void SAL_CALL java_sql_Statement_Base::release() throw() +{ + java_sql_Statement_BASE::release(); +} + +void SAL_CALL java_sql_Statement::acquire() throw() +{ + OStatement_BASE2::acquire(); +} + +void SAL_CALL java_sql_Statement::release() throw() +{ + OStatement_BASE2::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL java_sql_Statement_Base::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Object.cxx b/connectivity/source/drivers/jdbc/Object.cxx new file mode 100644 index 000000000..479699750 --- /dev/null +++ b/connectivity/source/drivers/jdbc/Object.cxx @@ -0,0 +1,483 @@ +/* -*- 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 <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/logging/LogLevel.hpp> +#include <java/tools.hxx> +#include <java/sql/SQLException.hxx> +#include <osl/diagnose.h> +#include <java/LocalRef.hxx> +#include <strings.hxx> + +#include <comphelper/logging.hxx> +#include <cppuhelper/exc_hlp.hxx> + +#include <memory> + +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; + + +static ::rtl::Reference< jvmaccess::VirtualMachine > const & getJavaVM2(const ::rtl::Reference< jvmaccess::VirtualMachine >& _rVM = ::rtl::Reference< jvmaccess::VirtualMachine >(), + bool _bSet = false) +{ + static ::rtl::Reference< jvmaccess::VirtualMachine > s_VM; + if ( _rVM.is() || _bSet ) + s_VM = _rVM; + return s_VM; +} + +::rtl::Reference< jvmaccess::VirtualMachine > java_lang_Object::getVM(const Reference<XComponentContext >& _rxContext) +{ + ::rtl::Reference< jvmaccess::VirtualMachine > xVM = getJavaVM2(); + if ( !xVM.is() && _rxContext.is() ) + xVM = getJavaVM2(::connectivity::getJavaVM(_rxContext)); + + return xVM; +} + +SDBThreadAttach::SDBThreadAttach() + : m_aGuard(java_lang_Object::getVM()) + , pEnv(nullptr) +{ + pEnv = m_aGuard.getEnvironment(); + OSL_ENSURE(pEnv,"Environment is nULL!"); +} + +SDBThreadAttach::~SDBThreadAttach() +{ +} + +static oslInterlockedCount& getJavaVMRefCount() +{ + static oslInterlockedCount s_nRefCount = 0; + return s_nRefCount; +} + +void SDBThreadAttach::addRef() +{ + osl_atomic_increment(&getJavaVMRefCount()); +} + +void SDBThreadAttach::releaseRef() +{ + osl_atomic_decrement(&getJavaVMRefCount()); + if ( getJavaVMRefCount() == 0 ) + { + getJavaVM2(::rtl::Reference< jvmaccess::VirtualMachine >(),true); + } +} + +// static variables of the class +jclass java_lang_Object::theClass = nullptr; + +jclass java_lang_Object::getMyClass() const +{ + if( !theClass ) + theClass = findMyClass("java/lang/Object"); + return theClass; +} +// the actual constructor +java_lang_Object::java_lang_Object() + : object( nullptr ) +{ + SDBThreadAttach::addRef(); +} + +// the protected-constructor for the derived classes +java_lang_Object::java_lang_Object( JNIEnv * pXEnv, jobject myObj ) + : object( nullptr ) +{ + SDBThreadAttach::addRef(); + if( pXEnv && myObj ) + object = pXEnv->NewGlobalRef( myObj ); +} + +java_lang_Object::~java_lang_Object() COVERITY_NOEXCEPT_FALSE +{ + if( object ) + { + SDBThreadAttach t; + clearObject(*t.pEnv); + } + SDBThreadAttach::releaseRef(); +} +void java_lang_Object::clearObject(JNIEnv& rEnv) +{ + if( object ) + { + rEnv.DeleteGlobalRef( object ); + object = nullptr; + } +} + +void java_lang_Object::clearObject() +{ + if( object ) + { + SDBThreadAttach t; + clearObject(*t.pEnv); + } +} +// the protected-constructor for the derived classes +void java_lang_Object::saveRef( JNIEnv * pXEnv, jobject myObj ) +{ + OSL_ENSURE( myObj, "object in c++ -> Java Wrapper" ); + if( myObj ) + object = pXEnv->NewGlobalRef( myObj ); +} + + +OUString java_lang_Object::toString() const +{ + static jmethodID mID(nullptr); + return callStringMethod("toString",mID); +} + + +namespace +{ + bool lcl_translateJNIExceptionToUNOException( + JNIEnv* _pEnvironment, const Reference< XInterface >& _rxContext, SQLException& _out_rException ) + { + jthrowable jThrow = _pEnvironment ? _pEnvironment->ExceptionOccurred() : nullptr; + if ( !jThrow ) + return false; + + _pEnvironment->ExceptionClear(); + // we have to clear the exception here because we want to handle it itself + + if ( _pEnvironment->IsInstanceOf( jThrow, java_sql_SQLException_BASE::st_getMyClass() ) ) + { + std::unique_ptr< java_sql_SQLException_BASE > pException( new java_sql_SQLException_BASE( _pEnvironment, jThrow ) ); + _out_rException = SQLException( pException->getMessage(), _rxContext, + pException->getSQLState(), pException->getErrorCode(), Any() ); + return true; + } + else if ( _pEnvironment->IsInstanceOf( jThrow, java_lang_Throwable::st_getMyClass() ) ) + { + std::unique_ptr< java_lang_Throwable > pThrow( new java_lang_Throwable( _pEnvironment, jThrow ) ); +#if OSL_DEBUG_LEVEL > 0 + pThrow->printStackTrace(); +#endif + OUString sMessage = pThrow->getMessage(); + if ( sMessage.isEmpty() ) + sMessage = pThrow->getLocalizedMessage(); + if( sMessage.isEmpty() ) + sMessage = pThrow->toString(); + _out_rException = SQLException( sMessage, _rxContext, OUString(), -1, Any() ); + return true; + } + else + _pEnvironment->DeleteLocalRef( jThrow ); + return false; + } +} + + +void java_lang_Object::ThrowLoggedSQLException( const ::comphelper::EventLogger& _rLogger, JNIEnv* _pEnvironment, + const Reference< XInterface >& _rxContext ) +{ + SQLException aException; + if ( lcl_translateJNIExceptionToUNOException( _pEnvironment, _rxContext, aException ) ) + { + _rLogger.log( css::logging::LogLevel::SEVERE, STR_LOG_THROWING_EXCEPTION, aException.Message, aException.SQLState, aException.ErrorCode ); + throw aException; + } +} + +void java_lang_Object::ThrowSQLException( JNIEnv* _pEnvironment, const Reference< XInterface>& _rxContext ) +{ + SQLException aException; + if ( lcl_translateJNIExceptionToUNOException( _pEnvironment, _rxContext, aException ) ) + throw aException; +} + +void java_lang_Object::ThrowRuntimeException( JNIEnv* _pEnvironment, const Reference< XInterface>& _rxContext ) +{ + try + { + ThrowSQLException(_pEnvironment, _rxContext); + } + catch (const SQLException& e) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } +} + +void java_lang_Object::obtainMethodId_throwSQL(JNIEnv* _pEnv,const char* _pMethodName, const char* _pSignature,jmethodID& _inout_MethodID) const +{ + if ( !_inout_MethodID ) + { + _inout_MethodID = _pEnv->GetMethodID( getMyClass(), _pMethodName, _pSignature ); + OSL_ENSURE( _inout_MethodID, _pSignature ); + if ( !_inout_MethodID ) + throw SQLException(); + } // if ( !_inout_MethodID ) +} + +void java_lang_Object::obtainMethodId_throwRuntime(JNIEnv* _pEnv,const char* _pMethodName, const char* _pSignature,jmethodID& _inout_MethodID) const +{ + if ( !_inout_MethodID ) + { + _inout_MethodID = _pEnv->GetMethodID( getMyClass(), _pMethodName, _pSignature ); + OSL_ENSURE( _inout_MethodID, _pSignature ); + if ( !_inout_MethodID ) + throw RuntimeException(); + } // if ( !_inout_MethodID ) +} + + +bool java_lang_Object::callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const +{ + bool out( false ); + + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callBooleanMethod: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()Z", _inout_MethodID); + // call method + out = t.pEnv->CallBooleanMethod( object, _inout_MethodID ); + ThrowSQLException( t.pEnv, nullptr ); + + return out; +} + +bool java_lang_Object::callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const +{ + bool out( false ); + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callBooleanMethodWithIntArg: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)Z", _inout_MethodID); + // call method + out = t.pEnv->CallBooleanMethod( object, _inout_MethodID, _nArgument ); + ThrowSQLException( t.pEnv, nullptr ); + + return out; +} + +jobject java_lang_Object::callResultSetMethod( JNIEnv& _rEnv,const char* _pMethodName, jmethodID& _inout_MethodID ) const +{ + // call method + jobject out = callObjectMethod(&_rEnv,_pMethodName,"()Ljava/sql/ResultSet;", _inout_MethodID); + return out; +} + +sal_Int32 java_lang_Object::callIntMethod_ThrowSQL(const char* _pMethodName, jmethodID& _inout_MethodID) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()I", _inout_MethodID); + // call method + jint out( t.pEnv->CallIntMethod( object, _inout_MethodID ) ); + ThrowSQLException( t.pEnv, nullptr ); + return static_cast<sal_Int32>(out); +} + +sal_Int32 java_lang_Object::callIntMethod_ThrowRuntime(const char* _pMethodName, jmethodID& _inout_MethodID) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"()I", _inout_MethodID); + // call method + jint out( t.pEnv->CallIntMethod( object, _inout_MethodID ) ); + ThrowRuntimeException(t.pEnv, nullptr); + return static_cast<sal_Int32>(out); +} + +sal_Int32 java_lang_Object::callIntMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nArgument ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)I", _inout_MethodID); + // call method + jint out( t.pEnv->CallIntMethod( object, _inout_MethodID , _nArgument) ); + ThrowSQLException( t.pEnv, nullptr ); + return static_cast<sal_Int32>(out); +} + +sal_Int32 java_lang_Object::callIntMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nArgument ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(I)I", _inout_MethodID); + // call method + jint out( t.pEnv->CallIntMethod( object, _inout_MethodID , _nArgument) ); + ThrowRuntimeException(t.pEnv, nullptr); + return static_cast<sal_Int32>(out); +} + +void java_lang_Object::callVoidMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"()V", _inout_MethodID); + + // call method + t.pEnv->CallVoidMethod( object, _inout_MethodID ); + ThrowSQLException( t.pEnv, nullptr ); +} + +void java_lang_Object::callVoidMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"()V", _inout_MethodID); + + // call method + t.pEnv->CallVoidMethod( object, _inout_MethodID ); + ThrowRuntimeException(t.pEnv, nullptr); +} + +void java_lang_Object::callVoidMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(I)V", _inout_MethodID); + + // call method + t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument ); + ThrowSQLException( t.pEnv, nullptr ); +} + +void java_lang_Object::callVoidMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(I)V", _inout_MethodID); + + // call method + t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument ); + ThrowRuntimeException(t.pEnv, nullptr); +} + +void java_lang_Object::callVoidMethodWithBoolArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Z)V", _inout_MethodID); + // call method + t.pEnv->CallVoidMethod( object, _inout_MethodID,int(_nArgument) ); + ThrowSQLException( t.pEnv, nullptr ); +} + +void java_lang_Object::callVoidMethodWithBoolArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwRuntime(t.pEnv, _pMethodName,"(Z)V", _inout_MethodID); + // call method + t.pEnv->CallVoidMethod( object, _inout_MethodID,int(_nArgument) ); + ThrowRuntimeException(t.pEnv, nullptr); +} + +OUString java_lang_Object::callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callStringMethod: no Java environment anymore!" ); + + // call method + jstring out = static_cast<jstring>(callObjectMethod(t.pEnv,_pMethodName,"()Ljava/lang/String;", _inout_MethodID)); + return JavaString2String( t.pEnv, out ); +} + +jobject java_lang_Object::callObjectMethod( JNIEnv * _pEnv,const char* _pMethodName,const char* _pSignature, jmethodID& _inout_MethodID ) const +{ + // obtain method ID + obtainMethodId_throwSQL(_pEnv, _pMethodName,_pSignature, _inout_MethodID); + // call method + jobject out = _pEnv->CallObjectMethod( object, _inout_MethodID); + ThrowSQLException( _pEnv, nullptr ); + return out; +} + + +jobject java_lang_Object::callObjectMethodWithIntArg( JNIEnv * _pEnv,const char* _pMethodName,const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const +{ + obtainMethodId_throwSQL(_pEnv, _pMethodName,_pSignature, _inout_MethodID); + // call method + jobject out = _pEnv->CallObjectMethod( object, _inout_MethodID,_nArgument ); + ThrowSQLException( _pEnv, nullptr ); + return out; +} + +OUString java_lang_Object::callStringMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callStringMethod: no Java environment anymore!" ); + jstring out = static_cast<jstring>(callObjectMethodWithIntArg(t.pEnv,_pMethodName,"(I)Ljava/lang/String;",_inout_MethodID,_nArgument)); + return JavaString2String( t.pEnv, out ); +} + +void java_lang_Object::callVoidMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethod: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Ljava/lang/String;)V", _inout_MethodID); + + jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,_nArgument)); + // call method + t.pEnv->CallVoidMethod( object, _inout_MethodID , str.get()); + ThrowSQLException( t.pEnv, nullptr ); +} + +sal_Int32 java_lang_Object::callIntMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const +{ + SDBThreadAttach t; + OSL_ENSURE( t.pEnv, "java_lang_Object::callIntMethodWithStringArg: no Java environment anymore!" ); + obtainMethodId_throwSQL(t.pEnv, _pMethodName,"(Ljava/lang/String;)I", _inout_MethodID); + + //TODO: Check if the code below is needed + //jdbc::LocalRef< jstring > str( t.env(), convertwchar_tToJavaString( t.pEnv, sql ) ); + //{ + // jdbc::ContextClassLoaderScope ccl( t.env(), + // m_pConnection ? m_pConnection->getDriverClassLoader() : jdbc::GlobalRef< jobject >(), + // m_aLogger, + // *this + // ); + + jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,_nArgument)); + // call method + jint out = t.pEnv->CallIntMethod( object, _inout_MethodID , str.get()); + ThrowSQLException( t.pEnv, nullptr ); + return static_cast<sal_Int32>(out); +} + +jclass java_lang_Object::findMyClass(const char* _pClassName) +{ + // the class must be fetched only once, therefore static + SDBThreadAttach t; + jclass tempClass = t.pEnv->FindClass(_pClassName); OSL_ENSURE(tempClass,"Java : FindClass not successful!"); + if(!tempClass) + { + t.pEnv->ExceptionDescribe(); + t.pEnv->ExceptionClear(); + } + jclass globClass = static_cast<jclass>(t.pEnv->NewGlobalRef( tempClass )); + t.pEnv->DeleteLocalRef( tempClass ); + return globClass; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/PreparedStatement.cxx b/connectivity/source/drivers/jdbc/PreparedStatement.cxx new file mode 100644 index 000000000..34c28f084 --- /dev/null +++ b/connectivity/source/drivers/jdbc/PreparedStatement.cxx @@ -0,0 +1,697 @@ +/* -*- 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 <java/sql/PreparedStatement.hxx> +#include <java/sql/ResultSet.hxx> +#include <java/sql/ResultSetMetaData.hxx> +#include <java/sql/Connection.hxx> +#include <java/sql/Timestamp.hxx> +#include <java/math/BigDecimal.hxx> +#include <java/tools.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/FValue.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> +#include <java/LocalRef.hxx> +#include <strings.hxx> +#include <string.h> +#include <memory> + +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; + + +//************ Class: java.sql.PreparedStatement + +IMPLEMENT_SERVICE_INFO(java_sql_PreparedStatement,"com.sun.star.sdbcx.JPreparedStatement","com.sun.star.sdbc.PreparedStatement"); + +java_sql_PreparedStatement::java_sql_PreparedStatement( JNIEnv * pEnv, java_sql_Connection& _rCon, const OUString& sql ) + : OStatement_BASE2( pEnv, _rCon ) +{ + m_sSqlStatement = sql; +} + +jclass java_sql_PreparedStatement::theClass = nullptr; + +java_sql_PreparedStatement::~java_sql_PreparedStatement() +{ +} + + +jclass java_sql_PreparedStatement::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/PreparedStatement"); + return theClass; +} + + +css::uno::Any SAL_CALL java_sql_PreparedStatement::queryInterface( const css::uno::Type & rType ) +{ + css::uno::Any aRet = OStatement_BASE2::queryInterface(rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface( rType, + static_cast< XPreparedStatement*>(this), + static_cast< XParameters*>(this), + static_cast< XResultSetMetaDataSupplier*>(this), + static_cast< XPreparedBatchExecution*>(this)); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL java_sql_PreparedStatement::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<XPreparedStatement>::get(), + cppu::UnoType<XParameters>::get(), + cppu::UnoType<XResultSetMetaDataSupplier>::get(), + cppu::UnoType<XPreparedBatchExecution>::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE2::getTypes()); +} + + +sal_Bool SAL_CALL java_sql_PreparedStatement::execute( ) +{ + m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTING_PREPARED ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + return callBooleanMethod( "execute", mID ); +} + + +sal_Int32 SAL_CALL java_sql_PreparedStatement::executeUpdate( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTING_PREPARED_UPDATE ); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + return callIntMethod_ThrowSQL("executeUpdate", mID); +} + + +void SAL_CALL java_sql_PreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + m_aLogger.log( LogLevel::FINER, STR_LOG_STRING_PARAMETER, parameterIndex, x ); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { // initialize temporary Variable + createStatement(t.pEnv); + static const char * const cSignature = "(ILjava/lang/String;)V"; + static const char * const cMethodName = "setString"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,x)); + t.pEnv->CallVoidMethod( object, mID, parameterIndex,str.get()); + // and clean up + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } //t.pEnv +} + + +css::uno::Reference< css::sdbc::XConnection > SAL_CALL java_sql_PreparedStatement::getConnection( ) +{ + return Reference< XConnection >(m_pConnection.get()); +} + + +css::uno::Reference< css::sdbc::XResultSet > SAL_CALL java_sql_PreparedStatement::executeQuery( ) +{ + m_aLogger.log( LogLevel::FINE, STR_LOG_EXECUTING_PREPARED_QUERY ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callResultSetMethod(t.env(),"executeQuery",mID); + + return out==nullptr ? nullptr : new java_sql_ResultSet( t.pEnv, out, m_aLogger, *m_pConnection,this); +} + + +void SAL_CALL java_sql_PreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_BOOLEAN_PARAMETER, parameterIndex, bool(x) ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setBoolean", "(IZ)V", mID, parameterIndex, x); +} + + +void SAL_CALL java_sql_PreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_BYTE_PARAMETER, parameterIndex, static_cast<sal_Int32>(x) ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setByte", "(IB)V", mID, parameterIndex, x); +} + + +void SAL_CALL java_sql_PreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_DATE_PARAMETER, parameterIndex, x ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + java_sql_Date aT(x); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setDate", "(ILjava/sql/Date;)V", mID, parameterIndex, aT.getJavaObject()); +} + + +void SAL_CALL java_sql_PreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_TIME_PARAMETER, parameterIndex, x ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + java_sql_Time aT(x); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setTime", "(ILjava/sql/Time;)V", mID, parameterIndex, aT.getJavaObject()); +} + + +void SAL_CALL java_sql_PreparedStatement::setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_TIMESTAMP_PARAMETER, parameterIndex, x ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + java_sql_Timestamp aD(x); + callVoidMethod_ThrowSQL("setTimestamp", "(ILjava/sql/Timestamp;)V", mID, parameterIndex, aD.getJavaObject()); +} + +void SAL_CALL java_sql_PreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_DOUBLE_PARAMETER, parameterIndex, x ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setDouble", "(ID)V", mID, parameterIndex, x); +} + + +void SAL_CALL java_sql_PreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_FLOAT_PARAMETER, parameterIndex, x ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setFloat", "(IF)V", mID, parameterIndex, x); +} + + +void SAL_CALL java_sql_PreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_INT_PARAMETER, parameterIndex, x ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setInt", "(II)V", mID, parameterIndex, x); +} + + +void SAL_CALL java_sql_PreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_LONG_PARAMETER, parameterIndex, x ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setLong", "(IJ)V", mID, parameterIndex, x); +} + + +void SAL_CALL java_sql_PreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_NULL_PARAMETER, parameterIndex, sqlType ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setNull", "(II)V", mID, parameterIndex, sqlType); +} + + +void SAL_CALL java_sql_PreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const css::uno::Reference< css::sdbc::XClob >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setClob", *this ); +} + + +void SAL_CALL java_sql_PreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const css::uno::Reference< css::sdbc::XBlob >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setBlob", *this ); +} + + +void SAL_CALL java_sql_PreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const css::uno::Reference< css::sdbc::XArray >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setArray", *this ); +} + + +void SAL_CALL java_sql_PreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const css::uno::Reference< css::sdbc::XRef >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setRef", *this ); +} + + +void SAL_CALL java_sql_PreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_OBJECT_NULL_PARAMETER, parameterIndex ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + createStatement(t.pEnv); + + // initialize temporary Variable + static const char * const cSignature = "(ILjava/lang/Object;II)V"; + static const char * const cMethodName = "setObject"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + { + jobject obj = nullptr; + switch(targetSqlType) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + { + double nTemp = 0.0; + + std::unique_ptr<java_math_BigDecimal> pBigDecimal; + if ( x >>= nTemp) + { + pBigDecimal.reset(new java_math_BigDecimal(nTemp)); + //setDouble(parameterIndex,nTemp); + //return; + } + else + { + ORowSetValue aValue; + aValue.fill(x); + const OUString sValue = aValue; + if ( !sValue.isEmpty() ) + pBigDecimal.reset(new java_math_BigDecimal(sValue)); + else + pBigDecimal.reset(new java_math_BigDecimal(0.0)); + } + //obj = convertwchar_tToJavaString(t.pEnv,::comphelper::getString(x)); + t.pEnv->CallVoidMethod( object, mID, parameterIndex,pBigDecimal->getJavaObject(),targetSqlType,scale); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + return; + } + default: + obj = convertwchar_tToJavaString(t.pEnv,::comphelper::getString(x)); + break; + } + t.pEnv->CallVoidMethod( object, mID, parameterIndex,obj,targetSqlType,scale); + t.pEnv->DeleteLocalRef(obj); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + // and clean up + } //mID + } //t.pEnv +} + + +void SAL_CALL java_sql_PreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/, const OUString& /*typeName*/ ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_OBJECT_NULL_PARAMETER, parameterIndex ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL<jobject>("setObject", "(ILjava/lang/Object;)V", mID, parameterIndex, nullptr); +} + + +void SAL_CALL java_sql_PreparedStatement::setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) +{ + if(!::dbtools::implSetObject(this,parameterIndex,x)) + { + const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution( + STR_UNKNOWN_PARA_TYPE, + "$position$", OUString::number(parameterIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } +} + + +void SAL_CALL java_sql_PreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_SHORT_PARAMETER, parameterIndex, x ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("setShort", "(IS)V", mID, parameterIndex, x); +} + + +void SAL_CALL java_sql_PreparedStatement::setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_BYTES_PARAMETER, parameterIndex ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + createStatement(t.pEnv); + + // initialize temporary Variable + static const char * const cSignature = "(I[B)V"; + static const char * const cMethodName = "setBytes"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + jbyteArray pByteArray = t.pEnv->NewByteArray(x.getLength()); + jbyte * pData = reinterpret_cast<jbyte *>( + const_cast<sal_Int8 *>(x.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between <http://docs.oracle.com/javase/6/docs/ + // technotes/guides/jni/spec/functions.html#wp22933> and + // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/ + // functions.html#wp22933>; work around that difference in a way + // that doesn't trigger loplugin:redundantcast + t.pEnv->SetByteArrayRegion(pByteArray,0,x.getLength(),pData); + t.pEnv->CallVoidMethod( object, mID, parameterIndex,pByteArray); + t.pEnv->DeleteLocalRef(pByteArray); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } //t.pEnv +} + + +void SAL_CALL java_sql_PreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_CHARSTREAM_PARAMETER, parameterIndex ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; + assert(t.pEnv && "Java environment has been deleted!"); + { + createStatement(t.pEnv); + + // initialize temporary variable + static const char * const cSignature = "(ILjava/io/InputStream;I)V"; + static const char * const cMethodName = "setCharacterStream"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + Sequence< sal_Int8 > aSeq; + if ( x.is() ) + x->readBytes( aSeq, length ); + sal_Int32 actualLength = aSeq.getLength(); + + jvalue args2[3]; + jbyteArray pByteArray = t.pEnv->NewByteArray( actualLength ); + jbyte * aSeqData = reinterpret_cast<jbyte *>( + const_cast<sal_Int8 *>(aSeq.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between <http://docs.oracle.com/javase/6/docs/ + // technotes/guides/jni/spec/functions.html#wp22933> and + // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/ + // functions.html#wp22933>; work around that difference in a way + // that doesn't trigger loplugin:redundantcast + t.pEnv->SetByteArrayRegion(pByteArray,0,actualLength,aSeqData); + args2[0].l = pByteArray; + args2[1].i = 0; + args2[2].i = actualLength; + // Java-Call + jclass aClass = t.pEnv->FindClass("java/io/CharArrayInputStream"); + static jmethodID mID2 = nullptr; + if ( !mID2 ) + { + // initialize temporary variable + const char * const cSignatureStream = "([BII)V"; + mID2 = t.pEnv->GetMethodID( aClass, "<init>", cSignatureStream ); + } + jobject tempObj = nullptr; + if(mID2) + tempObj = t.pEnv->NewObjectA( aClass, mID2, args2 ); + + t.pEnv->CallVoidMethod( object, mID, parameterIndex,tempObj,actualLength); + // and clean up + t.pEnv->DeleteLocalRef(pByteArray); + t.pEnv->DeleteLocalRef(tempObj); + t.pEnv->DeleteLocalRef(aClass); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } //t.pEnv +} + + +void SAL_CALL java_sql_PreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_BINARYSTREAM_PARAMETER, parameterIndex ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + createStatement(t.pEnv); + // initialize temporary variable + static const char * const cSignature = "(ILjava/io/InputStream;I)V"; + static const char * const cMethodName = "setBinaryStream"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + { + Sequence< sal_Int8 > aSeq; + if ( x.is() ) + x->readBytes( aSeq, length ); + sal_Int32 actualLength = aSeq.getLength(); + + jvalue args2[3]; + jbyteArray pByteArray = t.pEnv->NewByteArray(actualLength); + jbyte * aSeqData = reinterpret_cast<jbyte *>( + const_cast<sal_Int8 *>(aSeq.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between <http://docs.oracle.com/javase/6/docs/ + // technotes/guides/jni/spec/functions.html#wp22933> and + // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/ + // functions.html#wp22933>; work around that difference in a way + // that doesn't trigger loplugin:redundantcast + t.pEnv->SetByteArrayRegion(pByteArray,0,actualLength,aSeqData); + args2[0].l = pByteArray; + args2[1].i = 0; + args2[2].i = actualLength; + + // Java-Call + jclass aClass = t.pEnv->FindClass("java/io/ByteArrayInputStream"); + static jmethodID mID2 = nullptr; + if ( !mID2 ) + { + // initialize temporary variable + const char * const cSignatureStream = "([BII)V"; + mID2 = t.pEnv->GetMethodID( aClass, "<init>", cSignatureStream ); + } + jobject tempObj = nullptr; + if(mID2) + tempObj = t.pEnv->NewObjectA( aClass, mID2, args2 ); + t.pEnv->CallVoidMethod( object, mID, parameterIndex,tempObj,actualLength); + // and clean up + t.pEnv->DeleteLocalRef(pByteArray); + t.pEnv->DeleteLocalRef(tempObj); + t.pEnv->DeleteLocalRef(aClass); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } //t.pEnv +} + + +void SAL_CALL java_sql_PreparedStatement::clearParameters( ) +{ + m_aLogger.log( LogLevel::FINER, STR_LOG_CLEAR_PARAMETERS ); + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + SDBThreadAttach t; + { + createStatement(t.pEnv); + + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("clearParameters",mID); + } //t.pEnv +} + +void SAL_CALL java_sql_PreparedStatement::clearBatch( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("clearBatch",mID); + } //t.pEnv +} + + +void SAL_CALL java_sql_PreparedStatement::addBatch( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + createStatement(t.pEnv); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("addBatch", mID); + } //t.pEnv +} + + +css::uno::Sequence< sal_Int32 > SAL_CALL java_sql_PreparedStatement::executeBatch( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + css::uno::Sequence< sal_Int32 > aSeq; + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jintArray out = static_cast<jintArray>(callObjectMethod(t.pEnv,"executeBatch","()[I", mID)); + if(out) + { + jboolean p = false; + aSeq.realloc(t.pEnv->GetArrayLength(out)); + memcpy(aSeq.getArray(),t.pEnv->GetIntArrayElements(out,&p),aSeq.getLength()); + t.pEnv->DeleteLocalRef(out); + } + return aSeq; +} + +css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL java_sql_PreparedStatement::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + createStatement(t.pEnv); + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/ResultSetMetaData;", mID); + + return out==nullptr ? nullptr : new java_sql_ResultSetMetaData( t.pEnv, out, *m_pConnection ); +} + +void SAL_CALL java_sql_PreparedStatement::acquire() throw() +{ + OStatement_BASE2::acquire(); +} + +void SAL_CALL java_sql_PreparedStatement::release() throw() +{ + OStatement_BASE2::release(); +} + +void java_sql_PreparedStatement::createStatement(JNIEnv* _pEnv) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(java_sql_Statement_BASE::rBHelper.bDisposed); + + if( !(!object && _pEnv) ) + return; + + // initialize temporary variable + static const char * const cMethodName = "prepareStatement"; + + jvalue args[1]; + // convert Parameter + args[0].l = convertwchar_tToJavaString(_pEnv,m_sSqlStatement); + // Java-Call + jobject out = nullptr; + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(Ljava/lang/String;II)Ljava/sql/PreparedStatement;"; + mID = _pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature ); + } + if( mID ) + { + out = _pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID, args[0].l ,m_nResultSetType,m_nResultSetConcurrency); + } + else + { + static jmethodID mID2 = nullptr; + if ( !mID2 ) + { + static const char * const cSignature2 = "(Ljava/lang/String;)Ljava/sql/PreparedStatement;"; + mID2 = _pEnv->GetMethodID( m_pConnection->getMyClass(), cMethodName, cSignature2 ); + } + if ( mID2 ) + out = _pEnv->CallObjectMethod( m_pConnection->getJavaObject(), mID2, args[0].l ); + } + _pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + ThrowLoggedSQLException( m_aLogger, _pEnv, *this ); + if ( out ) + object = _pEnv->NewGlobalRef( out ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Reader.cxx b/connectivity/source/drivers/jdbc/Reader.cxx new file mode 100644 index 000000000..8dd12157e --- /dev/null +++ b/connectivity/source/drivers/jdbc/Reader.cxx @@ -0,0 +1,179 @@ +/* -*- 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 <java/io/Reader.hxx> +#include <string.h> +#include <osl/diagnose.h> +using namespace connectivity; +using ::com::sun::star::uno::Sequence; + + +//************ Class: java.io.Reader + + +jclass java_io_Reader::theClass = nullptr; +java_io_Reader::java_io_Reader( JNIEnv * pEnv, jobject myObj ) + : java_lang_Object( pEnv, myObj ) +{ + SDBThreadAttach::addRef(); +} +java_io_Reader::~java_io_Reader() +{ + SDBThreadAttach::releaseRef(); +} + +jclass java_io_Reader::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/io/Reader"); + return theClass; +} + +sal_Int32 SAL_CALL java_io_Reader::readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) +{ + return readBytes(aData,nMaxBytesToRead); +} + +void SAL_CALL java_io_Reader::skipBytes( sal_Int32 nBytesToSkip ) +{ + static jmethodID mID(nullptr); + if(nBytesToSkip <= 0) + return; + + if(m_buf) + { + m_buf.reset(); + --nBytesToSkip; + } + + static_assert(sizeof(jchar) == 2, "I thought Java characters were UTF16 code units?"); + sal_Int32 nCharsToSkip = nBytesToSkip / sizeof(jchar); + callIntMethodWithIntArg_ThrowRuntime("skip",mID,nCharsToSkip); + if(nBytesToSkip % sizeof(jchar) != 0) + { + assert(nBytesToSkip % sizeof(jchar) == 1); + Sequence< sal_Int8 > aData(1); + assert(m_buf); + readBytes(aData, 1); + } +} + +sal_Int32 SAL_CALL java_io_Reader::available( ) +{ + if(m_buf) + return 1; + bool out; + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + static const char * const cSignature = "()Z"; + static const char * const cMethodName = "ready"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwRuntime(t.pEnv, cMethodName,cSignature, mID); + out = t.pEnv->CallBooleanMethod( object, mID); + ThrowRuntimeException(t.pEnv,*this); + } //t.pEnv + return (m_buf ? 1 : 0) + (out ? 1 : 0); // no way to tell *how much* is ready +} + +void SAL_CALL java_io_Reader::closeInput( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowRuntime("close", mID); +} + +sal_Int32 SAL_CALL java_io_Reader::readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) +{ + OSL_ENSURE(aData.getLength() >= nBytesToRead," Sequence is smaller than BytesToRead"); + + if(nBytesToRead == 0) + return 0; + + sal_Int8 *dst(aData.getArray()); + sal_Int32 nBytesWritten(0); + + if (m_buf) + { + if(!aData.hasElements()) + { + aData.realloc(1); + dst = aData.getArray(); + } + *dst = *m_buf; + m_buf.reset(); + ++nBytesWritten; + ++dst; + --nBytesToRead; + } + + if(nBytesToRead == 0) + return nBytesWritten; + + sal_Int32 nCharsToRead = (nBytesToRead + 1)/2; + + jint outChars(0); + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + + { + jcharArray pCharArray = t.pEnv->NewCharArray(nCharsToRead); + static const char * const cSignature = "([CII)I"; + static const char * const cMethodName = "read"; + // Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwRuntime(t.pEnv, cMethodName,cSignature, mID); + outChars = t.pEnv->CallIntMethod( object, mID, pCharArray, 0, nCharsToRead ); + if ( !outChars ) + { + if(nBytesWritten==0) + ThrowRuntimeException(t.pEnv,*this); + else + return 1; + } + if(outChars > 0) + { + static_assert(sizeof(jchar) == 2, "I thought Java characters were UTF16 code units?"); + const sal_Int32 jcs = sizeof(jchar); + const sal_Int32 outBytes = std::min(nBytesToRead, outChars*jcs); + assert(outBytes == outChars*jcs || outBytes == outChars*jcs - 1); + + jboolean p = JNI_FALSE; + if(aData.getLength() < nBytesWritten + outBytes) + { + aData.realloc(nBytesWritten + outBytes); + dst = aData.getArray() + nBytesWritten; + } + jchar *outBuf(t.pEnv->GetCharArrayElements(pCharArray,&p)); + + memcpy(dst, outBuf, outBytes); + nBytesWritten += outBytes; + if(outBytes < outChars*jcs) + { + assert(outChars*jcs - outBytes == 1); + assert(!m_buf); + m_buf = reinterpret_cast<char*>(outBuf)[outBytes]; + } + } + t.pEnv->DeleteLocalRef(pCharArray); + } //t.pEnv + return nBytesWritten; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Ref.cxx b/connectivity/source/drivers/jdbc/Ref.cxx new file mode 100644 index 000000000..ca8e2e112 --- /dev/null +++ b/connectivity/source/drivers/jdbc/Ref.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 <java/sql/Ref.hxx> + +using namespace connectivity; + +//************ Class: java.sql.Ref + + +jclass java_sql_Ref::theClass = nullptr; +java_sql_Ref::java_sql_Ref( JNIEnv * pEnv, jobject myObj ) +: java_lang_Object( pEnv, myObj ) +{ + SDBThreadAttach::addRef(); +} +java_sql_Ref::~java_sql_Ref() +{ + SDBThreadAttach::releaseRef(); +} + +jclass java_sql_Ref::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/Ref"); + return theClass; +} + +OUString SAL_CALL java_sql_Ref::getBaseTypeName( ) +{ + static jmethodID mID(nullptr); + return callStringMethod("getBaseTypeName",mID); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/ResultSet.cxx b/connectivity/source/drivers/jdbc/ResultSet.cxx new file mode 100644 index 000000000..238e78702 --- /dev/null +++ b/connectivity/source/drivers/jdbc/ResultSet.cxx @@ -0,0 +1,998 @@ +/* -*- 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 <java/lang/String.hxx> +#include <java/lang/Boolean.hxx> +#include <java/sql/ResultSet.hxx> +#include <java/math/BigDecimal.hxx> +#include <java/sql/JStatement.hxx> +#include <java/sql/SQLWarning.hxx> +#include <java/sql/Timestamp.hxx> +#include <java/sql/Array.hxx> +#include <java/sql/Ref.hxx> +#include <java/sql/Clob.hxx> +#include <java/sql/Blob.hxx> +#include <java/sql/ResultSetMetaData.hxx> +#include <java/io/InputStream.hxx> +#include <java/io/Reader.hxx> +#include <java/tools.hxx> +#include <comphelper/property.hxx> +#include <connectivity/CommonTools.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <TConnection.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> +#include <java/LocalRef.hxx> + +#include <string.h> +#include <memory> + +using namespace ::comphelper; + +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; + +IMPLEMENT_SERVICE_INFO(java_sql_ResultSet,"com.sun.star.sdbcx.JResultSet","com.sun.star.sdbc.ResultSet"); + +//************ Class: java.sql.ResultSet + + +jclass java_sql_ResultSet::theClass = nullptr; +java_sql_ResultSet::java_sql_ResultSet( JNIEnv * pEnv, jobject myObj, const java::sql::ConnectionLog& _rParentLogger,java_sql_Connection& _rConnection, java_sql_Statement_Base* pStmt) + :java_sql_ResultSet_BASE(m_aMutex) + ,java_lang_Object( pEnv, myObj ) + ,OPropertySetHelper(java_sql_ResultSet_BASE::rBHelper) + ,m_aLogger( _rParentLogger, java::sql::ConnectionLog::RESULTSET ) + ,m_pConnection(&_rConnection) +{ + SDBThreadAttach::addRef(); + osl_atomic_increment(&m_refCount); + if ( pStmt ) + m_xStatement = *pStmt; + + osl_atomic_decrement(&m_refCount); +} + +java_sql_ResultSet::~java_sql_ResultSet() +{ + if ( !java_sql_ResultSet_BASE::rBHelper.bDisposed && !java_sql_ResultSet_BASE::rBHelper.bInDispose ) + { + // increment ref count to prevent double call of Dtor + osl_atomic_increment( &m_refCount ); + dispose(); + } +} + +jclass java_sql_ResultSet::getMyClass() const +{ + // the class must be fetched only once, therefore static + if( !theClass ) + theClass = findMyClass("java/sql/ResultSet"); + return theClass; +} + +void java_sql_ResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + if( object ) + { + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("close", mID); + clearObject(*t.pEnv); + } + + SDBThreadAttach::releaseRef(); +} + +css::uno::Any SAL_CALL java_sql_ResultSet::queryInterface( const css::uno::Type & rType ) +{ + css::uno::Any aRet = OPropertySetHelper::queryInterface(rType); + return aRet.hasValue() ? aRet : java_sql_ResultSet_BASE::queryInterface(rType); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL java_sql_ResultSet::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(),java_sql_ResultSet_BASE::getTypes()); +} + + +sal_Int32 SAL_CALL java_sql_ResultSet::findColumn( const OUString& columnName ) +{ + static jmethodID mID(nullptr); + return callIntMethodWithStringArg("findColumn",mID,columnName); +} + +Reference< css::io::XInputStream > SAL_CALL java_sql_ResultSet::getBinaryStream( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getBinaryStream","(I)Ljava/io/InputStream;", mID, columnIndex); + + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_io_InputStream( t.pEnv, out ); +} + +Reference< css::io::XInputStream > SAL_CALL java_sql_ResultSet::getCharacterStream( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getCharacterStream","(I)Ljava/io/Reader;", mID, columnIndex); + + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_io_Reader( t.pEnv, out ); +} + + +sal_Bool SAL_CALL java_sql_ResultSet::getBoolean( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "getBoolean", mID,columnIndex ); +} + + +sal_Int8 SAL_CALL java_sql_ResultSet::getByte( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + jbyte (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallByteMethod; + return callMethodWithIntArg<jbyte>(pCallMethod,"getByte","(I)B",mID,columnIndex); +} + + +Sequence< sal_Int8 > SAL_CALL java_sql_ResultSet::getBytes( sal_Int32 columnIndex ) +{ + Sequence< sal_Int8 > aSeq; + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jbyteArray out = static_cast<jbyteArray>(callObjectMethodWithIntArg(t.pEnv,"getBytes","(I)[B", mID, columnIndex)); + if (out) + { + jboolean p = false; + aSeq.realloc(t.pEnv->GetArrayLength(out)); + memcpy(aSeq.getArray(),t.pEnv->GetByteArrayElements(out,&p),aSeq.getLength()); + t.pEnv->DeleteLocalRef(out); + } + return aSeq; +} + + +css::util::Date SAL_CALL java_sql_ResultSet::getDate( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getDate","(I)Ljava/sql/Date;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out ? static_cast <css::util::Date> (java_sql_Date( t.pEnv, out )) : css::util::Date(); +} + + +double SAL_CALL java_sql_ResultSet::getDouble( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + jdouble (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallDoubleMethod; + return callMethodWithIntArg<double>(pCallMethod,"getDouble","(I)D",mID,columnIndex); +} + + +float SAL_CALL java_sql_ResultSet::getFloat( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + jfloat (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallFloatMethod; + return callMethodWithIntArg<jfloat>(pCallMethod,"getFloat","(I)F",mID,columnIndex); +} + + +sal_Int32 SAL_CALL java_sql_ResultSet::getInt( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + return callIntMethodWithIntArg_ThrowSQL("getInt",mID,columnIndex); +} + + +sal_Int32 SAL_CALL java_sql_ResultSet::getRow( ) +{ + static jmethodID mID(nullptr); + return callIntMethod_ThrowSQL("getRow", mID); +} + + +sal_Int64 SAL_CALL java_sql_ResultSet::getLong( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + jlong (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallLongMethod; + return callMethodWithIntArg<jlong>(pCallMethod,"getLong","(I)J",mID,columnIndex); +} + + +css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL java_sql_ResultSet::getMetaData( ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getMetaData","()Ljava/sql/ResultSetMetaData;", mID); + + return out==nullptr ? nullptr : new java_sql_ResultSetMetaData( t.pEnv, out, *m_pConnection ); +} + +Reference< XArray > SAL_CALL java_sql_ResultSet::getArray( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getArray","(I)Ljava/sql/Array;", mID, columnIndex); + + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_Array( t.pEnv, out ); +} + + +Reference< XClob > SAL_CALL java_sql_ResultSet::getClob( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getClob","(I)Ljava/sql/Clob;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_Clob( t.pEnv, out ); +} + +Reference< XBlob > SAL_CALL java_sql_ResultSet::getBlob( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getBlob","(I)Ljava/sql/Blob;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_Blob( t.pEnv, out ); +} + + +Reference< XRef > SAL_CALL java_sql_ResultSet::getRef( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getRef","(I)Ljava/sql/Ref;", mID, columnIndex); + + // WARNING: the caller becomes the owner of the returned pointer + return out==nullptr ? nullptr : new java_sql_Ref( t.pEnv, out ); +} + + +Any SAL_CALL java_sql_ResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap ) +{ + jobject out(nullptr); + Any aRet; + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + { + jvalue args[2]; + // convert parameter + args[0].i = columnIndex; + args[1].l = convertTypeMapToJavaMap(typeMap); + // initialize temporary Variable + // Java-Call + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(I)Ljava/lang/Object;"; + static const char * const cMethodName = "getObject"; + + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + } + + out = t.pEnv->CallObjectMethodA( object, mID, args); + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l)); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + // and clean up + if ( out ) + { + if ( t.pEnv->IsInstanceOf(out,java_lang_String::st_getMyClass()) ) + { + java_lang_String aVal(t.pEnv,out); + aRet <<= OUString(aVal); + } + else if ( t.pEnv->IsInstanceOf(out,java_lang_Boolean::st_getMyClass()) ) + { + java_lang_Boolean aVal(t.pEnv,out); + static jmethodID methodID = nullptr; + aRet <<= aVal.callBooleanMethod("booleanValue",methodID); + } + else if ( t.pEnv->IsInstanceOf(out,java_sql_Date::st_getMyClass()) ) + { + java_sql_Date aVal(t.pEnv,out); + aRet <<= css::util::Date(aVal); + } + else if ( t.pEnv->IsInstanceOf(out,java_sql_Time::st_getMyClass()) ) + { + java_sql_Time aVal(t.pEnv,out); + aRet <<= css::util::Time(aVal); + } + else if ( t.pEnv->IsInstanceOf(out,java_sql_Timestamp::st_getMyClass()) ) + { + java_sql_Timestamp aVal(t.pEnv,out); + aRet <<= css::util::DateTime(aVal); + } + else + t.pEnv->DeleteLocalRef(out); + } + } //t.pEnv + return aRet; +} + + +sal_Int16 SAL_CALL java_sql_ResultSet::getShort( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + jshort (JNIEnv::* const pCallMethod)( jobject obj, jmethodID methodID, ... ) = &JNIEnv::CallShortMethod; + return callMethodWithIntArg<jshort>(pCallMethod,"getShort","(I)S",mID,columnIndex); +} + + +OUString SAL_CALL java_sql_ResultSet::getString( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getString",mID,columnIndex); +} + + +css::util::Time SAL_CALL java_sql_ResultSet::getTime( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getTime","(I)Ljava/sql/Time;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out ? static_cast <css::util::Time> (java_sql_Time( t.pEnv, out )) : css::util::Time(); +} + + +css::util::DateTime SAL_CALL java_sql_ResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + static jmethodID mID(nullptr); + jobject out = callObjectMethodWithIntArg(t.pEnv,"getTimestamp","(I)Ljava/sql/Timestamp;", mID, columnIndex); + // WARNING: the caller becomes the owner of the returned pointer + return out ? static_cast <css::util::DateTime> (java_sql_Timestamp( t.pEnv, out )) : css::util::DateTime(); +} + + +sal_Bool SAL_CALL java_sql_ResultSet::isAfterLast( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "isAfterLast", mID ); +} + +sal_Bool SAL_CALL java_sql_ResultSet::isFirst( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "isFirst", mID ); +} + +sal_Bool SAL_CALL java_sql_ResultSet::isLast( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "isLast", mID ); +} + +void SAL_CALL java_sql_ResultSet::beforeFirst( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("beforeFirst", mID); +} + +void SAL_CALL java_sql_ResultSet::afterLast( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("afterLast", mID); +} + + +void SAL_CALL java_sql_ResultSet::close( ) +{ + dispose(); +} + + +sal_Bool SAL_CALL java_sql_ResultSet::first( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "first", mID ); +} + + +sal_Bool SAL_CALL java_sql_ResultSet::last( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "last", mID ); +} + +sal_Bool SAL_CALL java_sql_ResultSet::absolute( sal_Int32 row ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "absolute", mID,row ); +} + +sal_Bool SAL_CALL java_sql_ResultSet::relative( sal_Int32 row ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "relative", mID,row ); +} + +sal_Bool SAL_CALL java_sql_ResultSet::previous( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "previous", mID ); +} + +Reference< XInterface > SAL_CALL java_sql_ResultSet::getStatement( ) +{ + return m_xStatement; +} + + +sal_Bool SAL_CALL java_sql_ResultSet::rowDeleted( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "rowDeleted", mID ); +} + +sal_Bool SAL_CALL java_sql_ResultSet::rowInserted( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "rowInserted", mID ); +} + +sal_Bool SAL_CALL java_sql_ResultSet::rowUpdated( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "rowUpdated", mID ); +} + + +sal_Bool SAL_CALL java_sql_ResultSet::isBeforeFirst( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "isBeforeFirst", mID ); +} + + +sal_Bool SAL_CALL java_sql_ResultSet::next( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "next", mID ); +} + +sal_Bool SAL_CALL java_sql_ResultSet::wasNull( ) +{ + static jmethodID mID(nullptr); + return callBooleanMethod( "wasNull", mID ); +} + +void SAL_CALL java_sql_ResultSet::cancel( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowRuntime("cancel", mID); +} + +void SAL_CALL java_sql_ResultSet::clearWarnings( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("clearWarnings", mID); +} + +css::uno::Any SAL_CALL java_sql_ResultSet::getWarnings( ) +{ + SDBThreadAttach t; + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getWarnings","()Ljava/sql/SQLWarning;", mID); + // WARNING: the caller becomes the owner of the returned pointer + if( out ) + { + java_sql_SQLWarning_BASE warn_base( t.pEnv, out ); + return makeAny( + static_cast< css::sdbc::SQLException >( + java_sql_SQLWarning(warn_base,*this))); + } + + return css::uno::Any(); +} + + +void SAL_CALL java_sql_ResultSet::insertRow( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("insertRow", mID); +} + +void SAL_CALL java_sql_ResultSet::updateRow( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateRow", mID); +} + +void SAL_CALL java_sql_ResultSet::deleteRow( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("deleteRow", mID); +} + + +void SAL_CALL java_sql_ResultSet::cancelRowUpdates( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("cancelRowUpdates", mID); +} + + +void SAL_CALL java_sql_ResultSet::moveToInsertRow( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("moveToInsertRow", mID); +} + + +void SAL_CALL java_sql_ResultSet::moveToCurrentRow( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("moveToCurrentRow", mID); +} + + +void SAL_CALL java_sql_ResultSet::updateNull( sal_Int32 columnIndex ) +{ + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowSQL("updateNull", mID, columnIndex); +} + + +void SAL_CALL java_sql_ResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateBoolean", "(IZ)V", mID, columnIndex, x); +} + +void SAL_CALL java_sql_ResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateByte", "(IB)V", mID, columnIndex, x); +} + + +void SAL_CALL java_sql_ResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateShort", "(IS)V", mID, columnIndex, x); +} + +void SAL_CALL java_sql_ResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateInt", "(II)V", mID, columnIndex, x); +} + +void SAL_CALL java_sql_ResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateLong", "(IJ)V", mID, columnIndex, x); +} + + +void SAL_CALL java_sql_ResultSet::updateFloat( sal_Int32 columnIndex, float x ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateFloat", "(IF)V", mID, columnIndex, x); +} + + +void SAL_CALL java_sql_ResultSet::updateDouble( sal_Int32 columnIndex, double x ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateDouble", "(ID)V", mID, columnIndex, x); +} + + +void SAL_CALL java_sql_ResultSet::updateString( sal_Int32 columnIndex, const OUString& x ) +{ + SDBThreadAttach t; + + { + // initialize temporary variable + // Java-Call + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(ILjava/lang/String;)V"; + static const char * const cMethodName = "updateString"; + + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + } + + { + // convert parameter + jdbc::LocalRef< jstring > str( t.env(),convertwchar_tToJavaString(t.pEnv,x)); + t.pEnv->CallVoidMethod( object, mID,columnIndex,str.get()); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } +} + + +void SAL_CALL java_sql_ResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) +{ + SDBThreadAttach t; + + { + // initialize temporary variable + // Java-Call + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(I[B)V"; + static const char * const cMethodName = "updateBytes"; + + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + } + + { + jbyteArray aArray = t.pEnv->NewByteArray(x.getLength()); + jbyte * pData = reinterpret_cast<jbyte *>( + const_cast<sal_Int8 *>(x.getConstArray())); + // 4th param of Set*ArrayRegion changed from pointer to non-const to + // pointer to const between <http://docs.oracle.com/javase/6/docs/ + // technotes/guides/jni/spec/functions.html#wp22933> and + // <http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/ + // functions.html#wp22933>; work around that difference in a way + // that doesn't trigger loplugin:redundantcast + t.pEnv->SetByteArrayRegion(aArray,0,x.getLength(),pData); + // convert parameter + t.pEnv->CallVoidMethod( object, mID,columnIndex,aArray); + t.pEnv->DeleteLocalRef(aArray); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } +} + + +void SAL_CALL java_sql_ResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x ) +{ + java_sql_Date aD(x); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateDate", "(ILjava/sql/Date;)V", mID, columnIndex, aD.getJavaObject()); +} + + +void SAL_CALL java_sql_ResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x ) +{ + java_sql_Time aD(x); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateTime", "(ILjava/sql/Time;)V", mID, columnIndex, aD.getJavaObject()); +} + + +void SAL_CALL java_sql_ResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) +{ + java_sql_Timestamp aD(x); + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("updateTimestamp", "(ILjava/sql/Timestamp;)V", mID, columnIndex, aD.getJavaObject()); +} + + +void SAL_CALL java_sql_ResultSet::updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + try + { + SDBThreadAttach t; + { + + // initialize temporary variable + // Java-Call + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(ILjava/io/InputStream;I)V"; + static const char * const cMethodName = "updateBinaryStream"; + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + } + + { + // convert Parameter + jobject obj = createByteInputStream(x,length); + t.pEnv->CallVoidMethod( object, mID, columnIndex,obj,length); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } + } + catch(const Exception&) + { + Any anyEx = ::cppu::getCaughtException(); + ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::updateBinaryStream", *this, anyEx ); + } +} + +void SAL_CALL java_sql_ResultSet::updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + try + { + SDBThreadAttach t; + { + + // initialize temporary variable + // Java-Call + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(ILjava/io/Reader;I)V"; + static const char * const cMethodName = "updateCharacterStream"; + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + } + + { + // convert Parameter + jobject obj = createCharArrayReader(x,length); + t.pEnv->CallVoidMethod( object, mID, columnIndex,obj,length); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } + } + catch(const Exception&) + { + Any anyEx = ::cppu::getCaughtException(); + ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::updateCharacterStream", *this, anyEx ); + } +} + +void SAL_CALL java_sql_ResultSet::updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) +{ + if(!::dbtools::implUpdateObject(this,columnIndex,x)) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_UNKNOWN_COLUMN_TYPE, + "$position$", OUString::number(columnIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } +} + + +void SAL_CALL java_sql_ResultSet::updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) +{ + // OSL_FAIL("java_sql_ResultSet::updateNumericObject: NYI"); + try + { + SDBThreadAttach t; + + { + + // initialize temporary variable + // Java-Call + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(ILjava/lang/Object;I)V"; + static const char * const cMethodName = "updateObject"; + + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + } + + { + // convert parameter + double nTemp = 0.0; + std::unique_ptr<java_math_BigDecimal> pBigDecimal; + if ( x >>= nTemp) + { + pBigDecimal.reset(new java_math_BigDecimal(nTemp)); + } + else + pBigDecimal.reset(new java_math_BigDecimal(::comphelper::getString(x))); + + t.pEnv->CallVoidMethod( object, mID, columnIndex,pBigDecimal->getJavaObject(),scale); + ThrowLoggedSQLException( m_aLogger, t.pEnv, *this ); + } + } + } + catch(const Exception&) + { + updateObject( columnIndex,x); + } +} + +sal_Int32 java_sql_ResultSet::getResultSetConcurrency() const +{ + static jmethodID mID(nullptr); + return callIntMethod_ThrowRuntime("getConcurrency", mID); +} + +sal_Int32 java_sql_ResultSet::getResultSetType() const +{ + static jmethodID mID(nullptr); + return callIntMethod_ThrowRuntime("getType",mID); +} + +sal_Int32 java_sql_ResultSet::getFetchDirection() const +{ + static jmethodID mID(nullptr); + return callIntMethod_ThrowRuntime("getFetchDirection", mID); +} + +sal_Int32 java_sql_ResultSet::getFetchSize() const +{ + static jmethodID mID(nullptr); + return callIntMethod_ThrowRuntime("getFetchSize", mID); +} + +OUString java_sql_ResultSet::getCursorName() const +{ + static jmethodID mID(nullptr); + return callStringMethod("getCursorName",mID); +} + + +void java_sql_ResultSet::setFetchDirection(sal_Int32 _par0) +{ + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowRuntime("setFetchDirection", mID, _par0); +} + +void SAL_CALL java_sql_ResultSet::refreshRow( ) +{ + static jmethodID mID(nullptr); + callVoidMethod_ThrowSQL("refreshRow",mID); +} + +void java_sql_ResultSet::setFetchSize(sal_Int32 _par0) +{ + static jmethodID mID(nullptr); + callVoidMethodWithIntArg_ThrowRuntime("setFetchSize", mID, _par0); +} + +::cppu::IPropertyArrayHelper* java_sql_ResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps(5); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper & java_sql_ResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool java_sql_ResultSet::convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) +{ + bool bRet = false; + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + bRet = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection()); + break; + case PROPERTY_ID_FETCHSIZE: + bRet = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize()); + break; + default: + break; + } + return bRet; +} + + +void java_sql_ResultSet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) +{ + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr); + case PROPERTY_ID_FETCHDIRECTION: + setFetchDirection(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHSIZE: + setFetchSize(comphelper::getINT32(rValue)); + break; + default: + ; + } +} + +void java_sql_ResultSet::getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const +{ + try + { + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + rValue <<= getCursorName(); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= getResultSetConcurrency(); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= getResultSetType(); + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= getFetchDirection(); + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= getFetchSize(); + break; + } + } + catch(const Exception&) + { + } +} + +void SAL_CALL java_sql_ResultSet::acquire() throw() +{ + java_sql_ResultSet_BASE::acquire(); +} + +void SAL_CALL java_sql_ResultSet::release() throw() +{ + java_sql_ResultSet_BASE::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL java_sql_ResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/ResultSetMetaData.cxx b/connectivity/source/drivers/jdbc/ResultSetMetaData.cxx new file mode 100644 index 000000000..fdf5bfe69 --- /dev/null +++ b/connectivity/source/drivers/jdbc/ResultSetMetaData.cxx @@ -0,0 +1,200 @@ +/* -*- 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 <java/sql/ResultSetMetaData.hxx> +#include <java/sql/Connection.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; + + +//************ Class: java.sql.ResultSetMetaData + + +jclass java_sql_ResultSetMetaData::theClass = nullptr; +java_sql_ResultSetMetaData::java_sql_ResultSetMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rCon ) + :java_lang_Object( pEnv, myObj ) + ,m_pConnection( &_rCon ) + ,m_nColumnCount(-1) +{ + SDBThreadAttach::addRef(); +} +java_sql_ResultSetMetaData::~java_sql_ResultSetMetaData() +{ + SDBThreadAttach::releaseRef(); +} + +jclass java_sql_ResultSetMetaData::getMyClass() const +{ + // The class needs to be fetched just once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/sql/ResultSetMetaData"); + return theClass; +} + + +sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callIntMethodWithIntArg_ThrowSQL("getColumnDisplaySize",mID,column); +} + + +sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getColumnType( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callIntMethodWithIntArg_ThrowSQL("getColumnType",mID,column); +} + + +sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getColumnCount( ) +{ + if ( m_nColumnCount == -1 ) + { + static jmethodID mID(nullptr); + m_nColumnCount = callIntMethod_ThrowSQL("getColumnCount", mID); + } // if ( m_nColumnCount == -1 ) + return m_nColumnCount; + +} + + +sal_Bool SAL_CALL java_sql_ResultSetMetaData::isCaseSensitive( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "isCaseSensitive", mID,column ); +} + +OUString SAL_CALL java_sql_ResultSetMetaData::getSchemaName( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getSchemaName",mID,column); +} + + +OUString SAL_CALL java_sql_ResultSetMetaData::getColumnName( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getColumnName",mID,column); +} + +OUString SAL_CALL java_sql_ResultSetMetaData::getTableName( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getTableName",mID,column); +} + +OUString SAL_CALL java_sql_ResultSetMetaData::getCatalogName( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getCatalogName",mID,column); +} + +OUString SAL_CALL java_sql_ResultSetMetaData::getColumnTypeName( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getColumnTypeName",mID,column); +} + +OUString SAL_CALL java_sql_ResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getColumnLabel",mID,column); +} + +OUString SAL_CALL java_sql_ResultSetMetaData::getColumnServiceName( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callStringMethodWithIntArg("getColumnClassName",mID,column); +} + + +sal_Bool SAL_CALL java_sql_ResultSetMetaData::isCurrency( sal_Int32 column ) +{ + if ( m_pConnection->isIgnoreCurrencyEnabled() ) + return false; + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "isCurrency", mID,column ); +} + + +sal_Bool SAL_CALL java_sql_ResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "isAutoIncrement", mID,column ); +} + + +sal_Bool SAL_CALL java_sql_ResultSetMetaData::isSigned( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "isSigned", mID,column ); +} + +sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getPrecision( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callIntMethodWithIntArg_ThrowSQL("getPrecision",mID,column); +} + +sal_Int32 SAL_CALL java_sql_ResultSetMetaData::getScale( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callIntMethodWithIntArg_ThrowSQL("getScale",mID,column); +} + +sal_Int32 SAL_CALL java_sql_ResultSetMetaData::isNullable( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callIntMethodWithIntArg_ThrowSQL("isNullable",mID,column); +} + + +sal_Bool SAL_CALL java_sql_ResultSetMetaData::isSearchable( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "isSearchable", mID,column ); +} + + +sal_Bool SAL_CALL java_sql_ResultSetMetaData::isReadOnly( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "isReadOnly", mID,column ); +} + + +sal_Bool SAL_CALL java_sql_ResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "isDefinitelyWritable", mID,column ); +} + +sal_Bool SAL_CALL java_sql_ResultSetMetaData::isWritable( sal_Int32 column ) +{ + static jmethodID mID(nullptr); + return callBooleanMethodWithIntArg( "isWritable", mID,column ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/SQLException.cxx b/connectivity/source/drivers/jdbc/SQLException.cxx new file mode 100644 index 000000000..55bf0996c --- /dev/null +++ b/connectivity/source/drivers/jdbc/SQLException.cxx @@ -0,0 +1,87 @@ +/* -*- 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 <java/sql/SQLException.hxx> + +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::lang; + +//************ Class: java.sql.SQLException + +java_sql_SQLException::java_sql_SQLException( const java_sql_SQLException_BASE& _rException,const Reference< XInterface> & _rContext) + : css::sdbc::SQLException( _rException.getMessage(), + _rContext, + _rException.getSQLState(), + _rException.getErrorCode(), + makeAny(_rException.getNextException()) + ) +{ +} + +java_sql_SQLException_BASE::java_sql_SQLException_BASE( JNIEnv * pEnv, jobject myObj ) : java_lang_Exception( pEnv, myObj ) +{ +} + +jclass java_sql_SQLException_BASE::theClass = nullptr; + +java_sql_SQLException_BASE::~java_sql_SQLException_BASE() +{} + + +jclass java_sql_SQLException_BASE::getMyClass() const +{ + return st_getMyClass(); +} +jclass java_sql_SQLException_BASE::st_getMyClass() +{ + // The class needs to be fetched just once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/sql/SQLException"); + return theClass; +} + +css::sdbc::SQLException java_sql_SQLException_BASE::getNextException() const +{ + SDBThreadAttach t; + static jmethodID mID(nullptr); + jobject out = callObjectMethod(t.pEnv,"getNextException","()Ljava/sql/SQLException;", mID); + // WARNING: the caller will become the owner of the returned pointers !!! + if( out ) + { + java_sql_SQLException_BASE warn_base(t.pEnv,out); + return css::sdbc::SQLException(java_sql_SQLException(warn_base,nullptr)); + } + + return css::sdbc::SQLException(); +} + +OUString java_sql_SQLException_BASE::getSQLState() const +{ + static jmethodID mID(nullptr); + return callStringMethod("getSQLState",mID); +} +sal_Int32 java_sql_SQLException_BASE::getErrorCode() const +{ + static jmethodID mID(nullptr); + return callIntMethod_ThrowSQL("getErrorCode", mID); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/SQLWarning.cxx b/connectivity/source/drivers/jdbc/SQLWarning.cxx new file mode 100644 index 000000000..16616d18b --- /dev/null +++ b/connectivity/source/drivers/jdbc/SQLWarning.cxx @@ -0,0 +1,39 @@ +/* -*- 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 <java/sql/SQLWarning.hxx> +using namespace connectivity; + +//************ Class: java.sql.SQLWarning + + +jclass java_sql_SQLWarning_BASE::theClass = nullptr; + +java_sql_SQLWarning_BASE::~java_sql_SQLWarning_BASE() +{} + +jclass java_sql_SQLWarning_BASE::getMyClass() const +{ + // the class needs to be fetched only once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/sql/SQLWarning"); + return theClass; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/String.cxx b/connectivity/source/drivers/jdbc/String.cxx new file mode 100644 index 000000000..f7e682c02 --- /dev/null +++ b/connectivity/source/drivers/jdbc/String.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <java/lang/String.hxx> +#include <java/tools.hxx> +using namespace connectivity; + +//************ Class: java.lang.String + + +jclass java_lang_String::theClass = nullptr; + +java_lang_String::~java_lang_String() +{} + +jclass java_lang_String::getMyClass() const +{ + return st_getMyClass(); +} +jclass java_lang_String::st_getMyClass() +{ + // the class needs to be fetched only once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/lang/String"); + return theClass; +} + + +java_lang_String::operator OUString() +{ + SDBThreadAttach t; + if(!t.pEnv) + return OUString(); + return JavaString2String(t.pEnv, static_cast<jstring>(object)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Throwable.cxx b/connectivity/source/drivers/jdbc/Throwable.cxx new file mode 100644 index 000000000..c96f5532f --- /dev/null +++ b/connectivity/source/drivers/jdbc/Throwable.cxx @@ -0,0 +1,66 @@ +/* -*- 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 <java/lang/Throwable.hxx> + +using namespace connectivity; + +//************ Class: java.lang.Throwable + + +jclass java_lang_Throwable::theClass = nullptr; + +java_lang_Throwable::~java_lang_Throwable() +{} + +jclass java_lang_Throwable::getMyClass() const +{ + return st_getMyClass(); +} +jclass java_lang_Throwable::st_getMyClass() +{ + // the class needs to be fetched only once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/lang/Throwable"); + return theClass; +} + + +OUString java_lang_Throwable::getMessage() const +{ + static jmethodID mID(nullptr); + return callStringMethod("getMessage",mID); +} + + +OUString java_lang_Throwable::getLocalizedMessage() const +{ + static jmethodID mID(nullptr); + return callStringMethod("getLocalizedMessage",mID); +} + +#if OSL_DEBUG_LEVEL > 0 +void java_lang_Throwable::printStackTrace() const +{ + static jmethodID mID(nullptr); + return callVoidMethod_ThrowSQL("printStackTrace",mID); +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/Timestamp.cxx b/connectivity/source/drivers/jdbc/Timestamp.cxx new file mode 100644 index 000000000..eb7624719 --- /dev/null +++ b/connectivity/source/drivers/jdbc/Timestamp.cxx @@ -0,0 +1,189 @@ +/* -*- 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 <java/sql/Timestamp.hxx> +#include <java/tools.hxx> +#include <connectivity/dbconversion.hxx> +#include <osl/diagnose.h> + +using namespace ::comphelper; +using namespace connectivity; + +//************ Class: java.sql.Date + + +jclass java_sql_Date::theClass = nullptr; +java_sql_Date::java_sql_Date( const css::util::Date& _rOut ) : java_util_Date( nullptr, nullptr ) +{ + SDBThreadAttach t; + if( !t.pEnv ) + return; + jvalue args[1]; + // Convert parameters + OUString sDateStr = ::dbtools::DBTypeConversion::toDateString(_rOut); + args[0].l = convertwchar_tToJavaString(t.pEnv,sDateStr); + + // Turn of Java-Call for the constructor + // initialise temporary variables + jobject tempObj; + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(Ljava/lang/String;)Ljava/sql/Date;"; + mID = t.pEnv->GetStaticMethodID( getMyClass(), "valueOf", cSignature ); + } + OSL_ENSURE(mID,"Unknown method id!"); + tempObj = t.pEnv->CallStaticObjectMethod( getMyClass(), mID, args[0].l ); + saveRef( t.pEnv, tempObj ); + t.pEnv->DeleteLocalRef( tempObj ); + // and clean +} + +java_sql_Date::~java_sql_Date() +{} + +jclass java_sql_Date::getMyClass() const +{ + return st_getMyClass(); +} +jclass java_sql_Date::st_getMyClass() +{ + // the class needs only be fetched once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/sql/Date"); + return theClass; +} + + +java_sql_Date::operator css::util::Date() +{ + return ::dbtools::DBTypeConversion::toDate(toString()); +} + + +//************ Class: java.sql.Time + + +jclass java_sql_Time::theClass = nullptr; + +java_sql_Time::~java_sql_Time() +{} + +jclass java_sql_Time::getMyClass() const +{ + return st_getMyClass(); +} +jclass java_sql_Time::st_getMyClass() +{ + // the class needs only be fetched once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/sql/Time"); + return theClass; +} +java_sql_Time::java_sql_Time( const css::util::Time& _rOut ): java_util_Date( nullptr, nullptr ) +{ + SDBThreadAttach t; + if( !t.pEnv ) + return; + jvalue args[1]; + // Convert parameters + // java.sql.Time supports only whole seconds... + OUString sDateStr = ::dbtools::DBTypeConversion::toTimeStringS(_rOut); + args[0].l = convertwchar_tToJavaString(t.pEnv,sDateStr); + + // Turn off Java-Call for the constructor + // initialise temporary variables + jobject tempObj; + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(Ljava/lang/String;)Ljava/sql/Time;"; + mID = t.pEnv->GetStaticMethodID( getMyClass(), "valueOf", cSignature ); + } + OSL_ENSURE(mID,"Unknown method id!"); + tempObj = t.pEnv->CallStaticObjectMethod( getMyClass(), mID, args[0].l ); + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + saveRef( t.pEnv, tempObj ); + t.pEnv->DeleteLocalRef( tempObj ); + // and clean +} + +java_sql_Time::operator css::util::Time() +{ + return ::dbtools::DBTypeConversion::toTime(toString()); +} + +//************ Class: java.sql.Timestamp + + +jclass java_sql_Timestamp::theClass = nullptr; + +java_sql_Timestamp::~java_sql_Timestamp() +{} + +jclass java_sql_Timestamp::getMyClass() const +{ + return st_getMyClass(); +} + +jclass java_sql_Timestamp::st_getMyClass() +{ + // the class needs only be fetched once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/sql/Timestamp"); + return theClass; +} + +java_sql_Timestamp::java_sql_Timestamp(const css::util::DateTime& _rOut) + :java_util_Date( nullptr, nullptr ) +{ + SDBThreadAttach t; + if( !t.pEnv ) + return; + jvalue args[1]; + // Convert parameters + OUString sDateStr = ::dbtools::DBTypeConversion::toDateTimeString(_rOut); + + args[0].l = convertwchar_tToJavaString(t.pEnv,sDateStr); + + // Turn off Java-Call for the constructor + // initialise temporary variables + jobject tempObj; + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "(Ljava/lang/String;)Ljava/sql/Timestamp;"; + mID = t.pEnv->GetStaticMethodID( getMyClass(), "valueOf", cSignature ); + } + OSL_ENSURE(mID,"Unknown method id!"); + tempObj = t.pEnv->CallStaticObjectMethod( getMyClass(), mID, args[0].l ); + + saveRef( t.pEnv, tempObj ); + t.pEnv->DeleteLocalRef( tempObj ); + // and clean +} + + +java_sql_Timestamp::operator css::util::DateTime() +{ + return ::dbtools::DBTypeConversion::toDateTime(toString()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/jdbc.component b/connectivity/source/drivers/jdbc/jdbc.component new file mode 100644 index 000000000..07fd03c68 --- /dev/null +++ b/connectivity/source/drivers/jdbc/jdbc.component @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<!-- Recent Java 6 VMs make calls to JNI Attach/DetachCurrentThread (which this + code does extensively) very expensive. A follow-up JVM fix reduced the + overhead significantly again for all threads but the main thread. So a + quick hack to improve performance of this component again is to confine it + in the affine apartment (where all code will run on a single, dedicated + thread that is guaranteed no to be the main thread). However, a better fix + would still be to redesign the code so that it does not call + Attach/DetachCurrentThread so frequently: +--> + +<component loader="com.sun.star.loader.SharedLibrary" + environment="@CPPU_ENV@:affine" prefix="jdbc" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.JDBCDriver"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/jdbc/jservices.cxx b/connectivity/source/drivers/jdbc/jservices.cxx new file mode 100644 index 000000000..63ae84c8e --- /dev/null +++ b/connectivity/source/drivers/jdbc/jservices.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 <java/sql/Driver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* jdbc_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + java_sql_Driver::getImplementationName_Static(), + java_sql_Driver::getSupportedServiceNames_Static(), + java_sql_Driver_CreateInstance, + ::cppu::createSingleFactory); + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + pRet = aReq.getProvider(); + } + + return pRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/jdbc/tools.cxx b/connectivity/source/drivers/jdbc/tools.cxx new file mode 100644 index 000000000..5021d653a --- /dev/null +++ b/connectivity/source/drivers/jdbc/tools.cxx @@ -0,0 +1,262 @@ +/* -*- 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 <java/tools.hxx> +#include <java/util/Property.hxx> +#include <com/sun/star/sdbc/DriverPropertyInfo.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <connectivity/dbexception.hxx> +#include <osl/diagnose.h> + +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; + +void java_util_Properties::setProperty(const OUString& key, const OUString& value) +{ + SDBThreadAttach t; OSL_ENSURE(t.pEnv,"Java environment has been deleted!"); + jobject out(nullptr); + + { + jvalue args[2]; + // Convert Parameter + args[0].l = convertwchar_tToJavaString(t.pEnv,key); + args[1].l = convertwchar_tToJavaString(t.pEnv,value); + // Initialize temporary Variables + static const char * const cSignature = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;"; + static const char * const cMethodName = "setProperty"; + // Turn off Java-Call + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, cMethodName,cSignature, mID); + out = t.pEnv->CallObjectMethod(object, mID, args[0].l,args[1].l); + ThrowSQLException(t.pEnv,nullptr); + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[1].l)); + t.pEnv->DeleteLocalRef(static_cast<jstring>(args[0].l)); + ThrowSQLException(t.pEnv,nullptr); + if(out) + t.pEnv->DeleteLocalRef(out); + } //t.pEnv + // WARNING: The caller will be owner of the returned pointers!!! +} +jclass java_util_Properties::theClass = nullptr; + +java_util_Properties::~java_util_Properties() +{} + +jclass java_util_Properties::getMyClass() const +{ + // the class needs only be called once, that is why it is static + if( !theClass ) + theClass = findMyClass("java/util/Properties"); + return theClass; +} + + +java_util_Properties::java_util_Properties( ): java_lang_Object( nullptr, nullptr ) +{ + SDBThreadAttach t; + if( !t.pEnv ) + return; + // Turn off Java-Call for the constructor + // Initialize temporary Variables + static const char * const cSignature = "()V"; + jobject tempObj; + static jmethodID mID(nullptr); + obtainMethodId_throwSQL(t.pEnv, "<init>",cSignature, mID); + tempObj = t.pEnv->NewObject( getMyClass(), mID); + saveRef( t.pEnv, tempObj ); + t.pEnv->DeleteLocalRef( tempObj ); +} + + +jstring connectivity::convertwchar_tToJavaString(JNIEnv *pEnv,const OUString& _rTemp) +{ + OSL_ENSURE(pEnv,"Environment is NULL!"); + jstring pStr = pEnv->NewString( + reinterpret_cast<jchar const *>(_rTemp.getStr()), _rTemp.getLength()); + pEnv->ExceptionClear(); + OSL_ENSURE(pStr,"Could not create a jsstring object!"); + return pStr; +} + + +std::unique_ptr<java_util_Properties> connectivity::createStringPropertyArray(const Sequence< PropertyValue >& info ) +{ + std::unique_ptr<java_util_Properties> pProps(new java_util_Properties()); + const PropertyValue* pBegin = info.getConstArray(); + const PropertyValue* pEnd = pBegin + info.getLength(); + + for(;pBegin != pEnd;++pBegin) + { + // these are properties used internally by LibreOffice, + // and should not be passed to the JDBC driver + // (which probably does not know anything about them anyway). + if ( pBegin->Name != "JavaDriverClass" + && pBegin->Name != "JavaDriverClassPath" + && pBegin->Name != "SystemProperties" + && pBegin->Name != "CharSet" + && pBegin->Name != "AppendTableAliasName" + && pBegin->Name != "AppendTableAliasInSelect" + && pBegin->Name != "DisplayVersionColumns" + && pBegin->Name != "GeneratedValues" + && pBegin->Name != "UseIndexDirectionKeyword" + && pBegin->Name != "UseKeywordAsBeforeAlias" + && pBegin->Name != "AddIndexAppendix" + && pBegin->Name != "FormsCheckRequiredFields" + && pBegin->Name != "GenerateASBeforeCorrelationName" + && pBegin->Name != "EscapeDateTime" + && pBegin->Name != "ParameterNameSubstitution" + && pBegin->Name != "IsPasswordRequired" + && pBegin->Name != "IsAutoRetrievingEnabled" + && pBegin->Name != "AutoRetrievingStatement" + && pBegin->Name != "UseCatalogInSelect" + && pBegin->Name != "UseSchemaInSelect" + && pBegin->Name != "AutoIncrementCreation" + && pBegin->Name != "Extension" + && pBegin->Name != "NoNameLengthLimit" + && pBegin->Name != "EnableSQL92Check" + && pBegin->Name != "EnableOuterJoinEscape" + && pBegin->Name != "BooleanComparisonMode" + && pBegin->Name != "IgnoreCurrency" + && pBegin->Name != "TypeInfoSettings" + && pBegin->Name != "IgnoreDriverPrivileges" + && pBegin->Name != "ImplicitCatalogRestriction" + && pBegin->Name != "ImplicitSchemaRestriction" + && pBegin->Name != "SupportsTableCreation" + && pBegin->Name != "UseJava" + && pBegin->Name != "Authentication" + && pBegin->Name != "PreferDosLikeLineEnds" + && pBegin->Name != "PrimaryKeySupport" + && pBegin->Name != "RespectDriverResultSetType" + ) + { + OUString aStr; + OSL_VERIFY( pBegin->Value >>= aStr ); + pProps->setProperty(pBegin->Name,aStr); + } + } + return pProps; +} + +OUString connectivity::JavaString2String(JNIEnv *pEnv,jstring Str) +{ + OUString aStr; + if(Str) + { + jboolean bCopy(true); + const jchar* pChar = pEnv->GetStringChars(Str,&bCopy); + jsize len = pEnv->GetStringLength(Str); + aStr = OUString(reinterpret_cast<sal_Unicode const *>(pChar), len); + + if(bCopy) + pEnv->ReleaseStringChars(Str,pChar); + pEnv->DeleteLocalRef(Str); + } + return aStr; +} + +jobject connectivity::convertTypeMapToJavaMap(const Reference< css::container::XNameAccess > & _rMap) +{ + if ( _rMap.is() ) + { + css::uno::Sequence< OUString > aNames = _rMap->getElementNames(); + if ( aNames.hasElements() ) + ::dbtools::throwFeatureNotImplementedSQLException( "Type maps", nullptr ); + } + return nullptr; +} + +bool connectivity::isExceptionOccurred(JNIEnv *pEnv) +{ + if ( !pEnv ) + return false; + + jthrowable pThrowable = pEnv->ExceptionOccurred(); + bool bRet = pThrowable != nullptr; + if ( pThrowable ) + { + pEnv->ExceptionClear(); + pEnv->DeleteLocalRef(pThrowable); + } + + return bRet; +} + +jobject connectivity::createByteInputStream(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length) +{ + SDBThreadAttach t; + if( !t.pEnv || !x.is() ) + return nullptr; + // Turn off Java-Call for the constructor + // Initialize temporary variables + jclass clazz = java_lang_Object::findMyClass("java/io/ByteArrayInputStream"); + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "([B)V"; + mID = t.pEnv->GetMethodID( clazz, "<init>", cSignature ); + OSL_ENSURE( mID, cSignature ); + if ( !mID ) + throw SQLException(); + } // if ( !_inout_MethodID ) + jbyteArray pByteArray = t.pEnv->NewByteArray(length); + Sequence< sal_Int8 > aData; + x->readBytes(aData,length); + jboolean p = false; + memcpy(t.pEnv->GetByteArrayElements(pByteArray,&p),aData.getArray(),aData.getLength()); + jobject out = t.pEnv->NewObject( clazz, mID,pByteArray); + t.pEnv->DeleteLocalRef(pByteArray); + return out; +} + +jobject connectivity::createCharArrayReader(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length) +{ + SDBThreadAttach t; + if( !t.pEnv || !x.is() ) + return nullptr; + // Turn off Java-Call for the constructor + // Initialize temporary Variables + jclass clazz = java_lang_Object::findMyClass("java/io/CharArrayReader"); + static jmethodID mID(nullptr); + if ( !mID ) + { + static const char * const cSignature = "([C)V"; + mID = t.pEnv->GetMethodID( clazz, "<init>", cSignature ); + OSL_ENSURE( mID, cSignature ); + if ( !mID ) + throw SQLException(); + } // if ( !_inout_MethodID ) + jcharArray pCharArray = t.pEnv->NewCharArray(length); + Sequence< sal_Int8 > aData; + x->readBytes(aData,length); + jboolean p = false; + memcpy(t.pEnv->GetCharArrayElements(pCharArray,&p),aData.getArray(),aData.getLength()); + jobject out = t.pEnv->NewObject( clazz, mID,pCharArray); + t.pEnv->DeleteLocalRef(pCharArray); + return out; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabAddressBook.cxx b/connectivity/source/drivers/macab/MacabAddressBook.cxx new file mode 100644 index 000000000..09e489203 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabAddressBook.cxx @@ -0,0 +1,242 @@ +/* -*- 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 "MacabAddressBook.hxx" +#include "MacabRecords.hxx" +#include "MacabGroup.hxx" + +#include <vector> + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> +#include <connectivity/CommonTools.hxx> + +using namespace connectivity::macab; +using namespace ::com::sun::star::uno; + +namespace { + +void manageDuplicateGroups(std::vector<MacabGroup *> _xGroups) +{ + /* If we have two cases of groups, say, family, this makes it: + * family + * family (2) + */ + std::vector<MacabGroup *>::reverse_iterator iter1, iter2; + sal_Int32 count; + + for(iter1 = _xGroups.rbegin(); iter1 != _xGroups.rend(); ++iter1) + { + /* If the name matches the default table name, there is already + * (obviously) a conflict. So, start the count of groups with this + * name at 2 instead of 1. + */ + if( (*iter1)->getName() == MacabAddressBook::getDefaultTableName() ) + count = 2; + else + count = 1; + + iter2 = iter1; + for( ++iter2; iter2 != _xGroups.rend(); ++iter2) + { + if( (*iter1)->getName() == (*iter2)->getName() ) + { + count++; + } + } + + // duplicate! + if(count != 1) + { + OUString sName = (*iter1)->getName() + " (" + + OUString::number(count) + + ")"; + (*iter1)->setName(sName); + } + } +} + +} + +MacabAddressBook::MacabAddressBook( ) + : m_aAddressBook(ABGetSharedAddressBook()), + m_xMacabRecords(nullptr), + m_bRetrievedGroups(false) +{ +} + + +MacabAddressBook::~MacabAddressBook() +{ + if(m_xMacabRecords != nullptr) + { + delete m_xMacabRecords; + m_xMacabRecords = nullptr; + } + + for(MacabGroup* pMacabGroup : m_xMacabGroups) + delete pMacabGroup; + + m_bRetrievedGroups = false; +} + + +/* Get the address book's default table name. This is the table name that + * refers to the table containing _all_ records in the address book. + */ +const OUString & MacabAddressBook::getDefaultTableName() +{ + /* This string probably needs to be localized. */ + static const OUString aDefaultTableName + (OUString("Address Book")); + + return aDefaultTableName; +} + + +MacabRecords *MacabAddressBook::getMacabRecords() +{ + /* If the MacabRecords don't exist, create them. */ + if(m_xMacabRecords == nullptr) + { + m_xMacabRecords = new MacabRecords(m_aAddressBook); + m_xMacabRecords->setName(getDefaultTableName()); + m_xMacabRecords->initialize(); + } + + return m_xMacabRecords; +} + + +/* Get the MacabRecords for a given name: either a group name or the + * default table name. + */ +MacabRecords *MacabAddressBook::getMacabRecords(const OUString& _tableName) +{ + if(_tableName == getDefaultTableName()) + { + return getMacabRecords(); + } + else + { + return getMacabGroup(_tableName); + } +} + + +MacabRecords *MacabAddressBook::getMacabRecordsMatch(const OUString& _tableName) +{ + if(match(_tableName, getDefaultTableName(), '\0')) + { + return getMacabRecords(); + } + + return getMacabGroupMatch(_tableName); +} + + +std::vector<MacabGroup *> MacabAddressBook::getMacabGroups() +{ + /* If the MacabGroups haven't been created yet, create them. */ + if(!m_bRetrievedGroups) + { + /* If the MacabRecords haven't been created yet, create them. */ + if(m_xMacabRecords == nullptr) + { + m_xMacabRecords = new MacabRecords(m_aAddressBook); + m_xMacabRecords->setName(getDefaultTableName()); + m_xMacabRecords->initialize(); + } + + CFArrayRef allGroups = ABCopyArrayOfAllGroups(m_aAddressBook); + sal_Int32 nGroups = CFArrayGetCount(allGroups); + m_xMacabGroups = std::vector<MacabGroup *>(nGroups); + + sal_Int32 i; + ABGroupRef xGroup; + + /* Go through each group and create a MacabGroup out of it. */ + for(i = 0; i < nGroups; i++) + { + xGroup = static_cast<ABGroupRef>(const_cast<void *>(CFArrayGetValueAtIndex(allGroups, i))); + m_xMacabGroups[i] = new MacabGroup(m_aAddressBook, m_xMacabRecords, xGroup); + } + + CFRelease(allGroups); + + /* Manage duplicates. */ + manageDuplicateGroups(m_xMacabGroups); + m_bRetrievedGroups = true; + } + + return m_xMacabGroups; +} + + +MacabGroup *MacabAddressBook::getMacabGroup(OUString const & _groupName) +{ + // initialize groups if not already initialized + if(!m_bRetrievedGroups) + getMacabGroups(); + + sal_Int32 nGroups = m_xMacabGroups.size(); + sal_Int32 i; + + for(i = 0; i < nGroups; i++) + { + if(m_xMacabGroups[i] != nullptr) + { + if(m_xMacabGroups[i]->getName() == _groupName) + { + return m_xMacabGroups[i]; + } + } + } + + return nullptr; +} + + +MacabGroup *MacabAddressBook::getMacabGroupMatch(OUString const & _groupName) +{ + // initialize groups if not already initialized + if(!m_bRetrievedGroups) + getMacabGroups(); + + sal_Int32 nGroups = m_xMacabGroups.size(); + sal_Int32 i; + + for(i = 0; i < nGroups; i++) + { + if(m_xMacabGroups[i] != nullptr) + { + if(match(m_xMacabGroups[i]->getName(), _groupName, '\0')) + { + return m_xMacabGroups[i]; + } + } + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabAddressBook.hxx b/connectivity/source/drivers/macab/MacabAddressBook.hxx new file mode 100644 index 000000000..a74621ef2 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabAddressBook.hxx @@ -0,0 +1,65 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABADDRESSBOOK_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABADDRESSBOOK_HXX + +#include "MacabRecords.hxx" +#include "MacabGroup.hxx" + +#include <vector> + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> + +namespace connectivity +{ + namespace macab + { + class MacabAddressBook + { + protected: + ABAddressBookRef m_aAddressBook; + MacabRecords *m_xMacabRecords; + std::vector<MacabGroup *> m_xMacabGroups; + bool m_bRetrievedGroups; + + public: + MacabAddressBook(); + ~MacabAddressBook(); + static const OUString & getDefaultTableName(); + + MacabRecords *getMacabRecords(); + std::vector<MacabGroup *> getMacabGroups(); + + MacabGroup *getMacabGroup(const OUString& _groupName); + MacabRecords *getMacabRecords(const OUString& _tableName); + + MacabGroup *getMacabGroupMatch(const OUString& _groupName); + MacabRecords *getMacabRecordsMatch(const OUString& _tableName); + }; + + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABADDRESSBOOK_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabCatalog.cxx b/connectivity/source/drivers/macab/MacabCatalog.cxx new file mode 100644 index 000000000..96ff62fd5 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabCatalog.cxx @@ -0,0 +1,112 @@ +/* -*- 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 "MacabCatalog.hxx" +#include "MacabConnection.hxx" +#include "MacabTables.hxx" +#include <com/sun/star/sdbc/XRow.hpp> + +using namespace connectivity::macab; +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; + + +MacabCatalog::MacabCatalog(MacabConnection* _pCon) + : connectivity::sdbcx::OCatalog(_pCon), + m_pConnection(_pCon) +{ +} + +void MacabCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + Sequence< OUString > aTypes { "%" }; + Reference< XResultSet > xResult = m_xMetaData->getTables( + Any(), "%", "%", aTypes); + + if (xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + OUString aName; + // const OUString& sDot = MacabCatalog::getDot(); + + while (xResult->next()) + { + // aName = xRow->getString(2); + // aName += sDot; + aName = xRow->getString(3); + aVector.push_back(aName); + } + } + if (m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset( new MacabTables(m_xMetaData,*this,m_aMutex,aVector) ); +} + +void MacabCatalog::refreshViews() +{ +} + +void MacabCatalog::refreshGroups() +{ +} + +void MacabCatalog::refreshUsers() +{ +} + +const OUString& MacabCatalog::getDot() +{ + static const OUString sDot = "."; + return sDot; +} + + +// XTablesSupplier +Reference< XNameAccess > SAL_CALL MacabCatalog::getTables( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + try + { + if (!m_pTables) + refreshTables(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pTables.get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabCatalog.hxx b/connectivity/source/drivers/macab/MacabCatalog.hxx new file mode 100644 index 000000000..9c45ab1f1 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabCatalog.hxx @@ -0,0 +1,57 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCATALOG_HXX + +#include <sdbcx/VCatalog.hxx> + +namespace connectivity +{ + namespace macab + { + class MacabConnection; + + class MacabCatalog : public connectivity::sdbcx::OCatalog + { + MacabConnection* m_pConnection; // used to get the metadata + + public: + explicit MacabCatalog(MacabConnection* _pCon); + + MacabConnection* getConnection() const { return m_pConnection; } + + static const OUString& getDot(); + + // implementation of the pure virtual methods + virtual void refreshTables() override; + virtual void refreshViews() override; + virtual void refreshGroups() override; + virtual void refreshUsers() override; + + // XTablesSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( + ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabColumns.cxx b/connectivity/source/drivers/macab/MacabColumns.cxx new file mode 100644 index 000000000..6eaa51aa7 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabColumns.cxx @@ -0,0 +1,95 @@ +/* -*- 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 "MacabColumns.hxx" +#include "MacabTable.hxx" +#include "MacabTables.hxx" +#include "MacabCatalog.hxx" +#include <connectivity/sdbcx/VColumn.hxx> +#include <com/sun/star/sdbc/XRow.hpp> + +using namespace connectivity::macab; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::comphelper; +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; + + +sdbcx::ObjectType MacabColumns::createObject(const OUString& _rName) +{ + const Any aCatalog; + const OUString sCatalogName; + const OUString sSchemaName(m_pTable->getSchema()); + const OUString sTableName(m_pTable->getTableName()); + Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns( + aCatalog, sSchemaName, sTableName, _rName); + + sdbcx::ObjectType xRet; + if (xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + + while (xResult->next()) + { + if (xRow->getString(4) == _rName) + { + OColumn* pRet = new OColumn( + _rName, + xRow->getString(6), + xRow->getString(13), + xRow->getString(12), + xRow->getInt(11), + xRow->getInt(7), + xRow->getInt(9), + xRow->getInt(5), + false, + false, + false, + true, + sCatalogName, + sSchemaName, + sTableName); + xRet = pRet; + break; + } + } + } + + return xRet; +} + +void MacabColumns::impl_refresh() +{ + m_pTable->refreshColumns(); +} + +MacabColumns::MacabColumns( MacabTable* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) + : sdbcx::OCollection(*_pTable, true, _rMutex, _rVector), + m_pTable(_pTable) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabColumns.hxx b/connectivity/source/drivers/macab/MacabColumns.hxx new file mode 100644 index 000000000..36da039a9 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabColumns.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCOLUMNS_HXX + +#include "MacabTable.hxx" +#include <connectivity/sdbcx/VCollection.hxx> + +namespace connectivity +{ + namespace macab + { + class MacabColumns : public sdbcx::OCollection + { + protected: + MacabTable* m_pTable; + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + + public: + MacabColumns( MacabTable* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabConnection.cxx b/connectivity/source/drivers/macab/MacabConnection.cxx new file mode 100644 index 000000000..4e5a27354 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabConnection.cxx @@ -0,0 +1,318 @@ +/* -*- 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 "MacabConnection.hxx" +#include "MacabAddressBook.hxx" +#include "MacabDatabaseMetaData.hxx" +#include "MacabStatement.hxx" +#include "MacabPreparedStatement.hxx" +#include "MacabDriver.hxx" +#include "MacabCatalog.hxx" +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> + +using namespace connectivity::macab; +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::sdbcx; + +IMPLEMENT_SERVICE_INFO(MacabConnection, "com.sun.star.sdbc.drivers.MacabConnection", "com.sun.star.sdbc.Connection") + +MacabConnection::MacabConnection(MacabDriver* _pDriver) + : m_pAddressBook(nullptr), + m_pDriver(_pDriver) +{ + m_pDriver->acquire(); +} + +MacabConnection::~MacabConnection() +{ + if (!doIsClosed()) + doClose(); + + m_pDriver->release(); + m_pDriver = nullptr; +} + +void MacabConnection::construct(const OUString&, const Sequence< PropertyValue >&) +{ + osl_atomic_increment( &m_refCount ); + + // get the macOS shared address book + m_pAddressBook = new MacabAddressBook(); + + osl_atomic_decrement( &m_refCount ); +} +// XServiceInfo + +Reference< XStatement > SAL_CALL MacabConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // create a statement + // the statement can only be executed once + Reference< XStatement > xReturn = new MacabStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL MacabConnection::prepareStatement( const OUString& _sSql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // create a statement + // the statement can only be executed more than once + Reference< XPreparedStatement > xReturn = new MacabPreparedStatement(this, _sSql); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL MacabConnection::prepareCall( const OUString& ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // not implemented yet :-) a task to do + return nullptr; +} + +OUString SAL_CALL MacabConnection::nativeSQL( const OUString& _sSql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + // when you need to transform SQL92 to you driver specific you can do it here + + return _sSql; +} + +void SAL_CALL MacabConnection::setAutoCommit( sal_Bool ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + // here you have to set your commit mode please have a look at the jdbc documentation to get a clear explanation +} + +sal_Bool SAL_CALL MacabConnection::getAutoCommit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + // you have to distinguish which if you are in autocommit mode or not + // at normal case true should be fine here + + return true; +} + +void SAL_CALL MacabConnection::commit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // when you database does support transactions you should commit here +} + +void SAL_CALL MacabConnection::rollback( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // same as commit but for the other case +} + +sal_Bool SAL_CALL MacabConnection::isClosed( ) +{ + return doIsClosed(); +} + +bool MacabConnection::doIsClosed() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + // just simple -> we are closed when we are disposed, that means someone called dispose(); (XComponent) + return MacabConnection_BASE::rBHelper.bDisposed; +} + +Reference< XDatabaseMetaData > SAL_CALL MacabConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // here we have to create the class with biggest interface + // The answer is 42 :-) + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if (!xMetaData.is()) + { + xMetaData = new MacabDatabaseMetaData(this); // need the connection because it can return it + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +void SAL_CALL MacabConnection::setReadOnly( sal_Bool ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // set you connection to readonly +} + +sal_Bool SAL_CALL MacabConnection::isReadOnly( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // return if your connection to readonly + return false; +} + +void SAL_CALL MacabConnection::setCatalog( const OUString& ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // if your database doesn't work with catalogs you go to next method otherwise you know what to do +} + +OUString SAL_CALL MacabConnection::getCatalog( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + + // return your current catalog + return OUString(); +} + +void SAL_CALL MacabConnection::setTransactionIsolation( sal_Int32 ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // set your isolation level + // please have a look at @see com.sun.star.sdbc.TransactionIsolation +} + +sal_Int32 SAL_CALL MacabConnection::getTransactionIsolation( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + + // please have a look at @see com.sun.star.sdbc.TransactionIsolation + return TransactionIsolation::NONE; +} + +Reference< css::container::XNameAccess > SAL_CALL MacabConnection::getTypeMap( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + + // if your driver has special database types you can return it here + + return nullptr; +} + +void SAL_CALL MacabConnection::setTypeMap( const Reference< css::container::XNameAccess >& ) +{ + // the other way around +} + +// XCloseable +void SAL_CALL MacabConnection::close( ) +{ + doClose(); +} + +void MacabConnection::doClose() +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabConnection_BASE::rBHelper.bDisposed); + } + dispose(); +} + +// XWarningsSupplier +Any SAL_CALL MacabConnection::getWarnings( ) +{ + // when you collected some warnings -> return it + return Any(); +} + +void SAL_CALL MacabConnection::clearWarnings( ) +{ + // you should clear your collected warnings here +} + +void MacabConnection::disposing() +{ + // we noticed that we should be destroyed in near future so we have to dispose our statements + ::osl::MutexGuard aGuard(m_aMutex); + + for (auto& rxStatement : m_aStatements) + { + Reference< XComponent > xComp(rxStatement.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + } + m_aStatements.clear(); + + if (m_pAddressBook != nullptr) + { + delete m_pAddressBook; + m_pAddressBook = nullptr; + } + + m_xMetaData.clear(); + + MacabConnection_BASE::disposing(); +} + +Reference< XTablesSupplier > MacabConnection::createCatalog() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XTablesSupplier > xTab = m_xCatalog; + if (!m_xCatalog.is()) + { + MacabCatalog *pCat = new MacabCatalog(this); + xTab = pCat; + m_xCatalog = xTab; + } + return xTab; +} + +MacabAddressBook* MacabConnection::getAddressBook() const +{ + return m_pAddressBook; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* createMacabConnection( void* _pDriver ) +{ + MacabConnection* pConnection = new MacabConnection( static_cast< MacabDriver* >( _pDriver ) ); + // by definition, the pointer crossing library boundaries as void ptr is acquired once + pConnection->acquire(); + return pConnection; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabConnection.hxx b/connectivity/source/drivers/macab/MacabConnection.hxx new file mode 100644 index 000000000..6173b26dc --- /dev/null +++ b/connectivity/source/drivers/macab/MacabConnection.hxx @@ -0,0 +1,118 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCONNECTION_HXX + +#include <map> +#include <connectivity/CommonTools.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <cppuhelper/compbase.hxx> +#include <TConnection.hxx> + +namespace connectivity +{ + namespace macab + { + + typedef ::cppu::WeakComponentImplHelper<css::sdbc::XConnection, + css::sdbc::XWarningsSupplier, + css::lang::XServiceInfo + > OMetaConnection_BASE; + + class MacabDriver; + class MacabAddressBook; + + typedef std::vector< css::uno::WeakReferenceHelper > OWeakRefArray; + + typedef connectivity::OMetaConnection MacabConnection_BASE; + + class MacabConnection : public MacabConnection_BASE + { + protected: + + // Data attributes + + MacabAddressBook* m_pAddressBook; // the address book + MacabDriver* m_pDriver; // pointer to the owning driver object + css::uno::Reference< css::sdbcx::XTablesSupplier> + m_xCatalog; // needed for the SQL interpreter + + private: + bool doIsClosed(); + + void doClose(); + + public: + /// @throws css::sdbc::SQLException + virtual void construct( const OUString& url,const css::uno::Sequence< css::beans::PropertyValue >& info); + + explicit MacabConnection(MacabDriver* _pDriver); + virtual ~MacabConnection() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + // XCloseable + virtual void SAL_CALL close( ) override; + + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + + // needed for the SQL interpreter + css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog(); + + // accessors + MacabDriver* getDriver() const { return m_pDriver;} + MacabAddressBook* getAddressBook() const; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx b/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx new file mode 100644 index 000000000..809537c23 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabDatabaseMetaData.cxx @@ -0,0 +1,1076 @@ +/* -*- 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 "MacabDatabaseMetaData.hxx" +#include "MacabAddressBook.hxx" +#include "MacabHeader.hxx" +#include "MacabGroup.hxx" +#include "macabutilities.hxx" + +#include "MacabDriver.hxx" +#include <FDatabaseMetaDataResultSet.hxx> +#include <OTypeInfo.hxx> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> + +#include <vector> + +using namespace connectivity::macab; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +MacabDatabaseMetaData::MacabDatabaseMetaData(MacabConnection* _pCon) + : m_xConnection(_pCon), + m_bUseCatalog(true) +{ + OSL_ENSURE(_pCon,"MacabDatabaseMetaData::MacabDatabaseMetaData: No connection set!"); + + osl_atomic_increment( &m_refCount ); + m_bUseCatalog = !(usesLocalFiles() || usesLocalFilePerTable()); + osl_atomic_decrement( &m_refCount ); +} + +MacabDatabaseMetaData::~MacabDatabaseMetaData() +{ +} + +OUString SAL_CALL MacabDatabaseMetaData::getCatalogSeparator( ) +{ + if (m_bUseCatalog) + { // do some special here for you database + } + + return OUString(); +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxRowSize( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCatalogNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCharLiteralLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInIndex( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxCursorNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxConnections( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInTable( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxStatementLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxTableNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxTablesInSelect( ) +{ + // MaxTablesInSelect describes how many tables can participate in the FROM part of a given SELECT statement, + // currently, the resultset/statement implementations can cope with one table only + return 1; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::storesMixedCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsAlterTableWithAddColumn( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsAlterTableWithDropColumn( ) +{ + return false; +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxIndexLength( ) +{ + return 0; // 0 means no limit +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsNonNullableColumns( ) +{ + return false; +} + +OUString SAL_CALL MacabDatabaseMetaData::getCatalogTerm( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getIdentifierQuoteString( ) +{ + // normally this is " + return "\""; +} + +OUString SAL_CALL MacabDatabaseMetaData::getExtraNameCharacters( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::isCatalogAtStart( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + return true; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + return true; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + return true; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + return true; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsPositionedDelete( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsPositionedUpdate( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInDataManipulation( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92FullSQL( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + return true; // should be supported at least +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInTableDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInTableDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInDataManipulation( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOuterJoins( ) +{ + return false; +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxStatements( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxProcedureNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxSchemaNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::allProceduresAreCallable( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsStoredProcedures( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSelectForUpdate( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::allTablesAreSelectable( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::isReadOnly( ) +{ + // for the moment, we have read-only addresses, but this might change in the future + return true; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::usesLocalFiles( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::usesLocalFilePerTable( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTypeConversion( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::nullPlusNonNullIsNull( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsColumnAliasing( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsTableCorrelationNames( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupBy( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsGroupByUnrelated( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMultipleTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMultipleResultSets( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsLikeEscapeClause( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsOrderByUnrelated( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsUnion( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsUnionAll( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMixedCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedAtEnd( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedAtStart( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedHigh( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::nullsAreSortedLow( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInExists( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInIns( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + return false; +} + +OUString SAL_CALL MacabDatabaseMetaData::getURL( ) +{ + // if someday we support more than the default address book, + // this method should return the URL which was used to create it + return "sdbc:address:macab:"; +} + +OUString SAL_CALL MacabDatabaseMetaData::getUserName( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getDriverName( ) +{ + return "macab"; +} + +OUString SAL_CALL MacabDatabaseMetaData::getDriverVersion() +{ + return MACAB_DRIVER_VERSION; +} + +OUString SAL_CALL MacabDatabaseMetaData::getDatabaseProductVersion( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getDatabaseProductName( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getProcedureTerm( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getSchemaTerm( ) +{ + return OUString(); +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getDriverMajorVersion( ) +{ + return MACAB_DRIVER_VERSION_MAJOR; +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getDefaultTransactionIsolation( ) +{ + return TransactionIsolation::NONE; +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getDriverMinorVersion( ) +{ + return MACAB_DRIVER_VERSION_MINOR; +} + +OUString SAL_CALL MacabDatabaseMetaData::getSQLKeywords( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getSearchStringEscape( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getStringFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getTimeDateFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getSystemFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL MacabDatabaseMetaData::getNumericFunctions( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsCoreSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + return true; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsFullOuterJoins( ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return false; +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxColumnsInSelect( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL MacabDatabaseMetaData::getMaxUserNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsResultSetType( sal_Int32 setType ) +{ + switch (setType) + { + case ResultSetType::FORWARD_ONLY: + case ResultSetType::SCROLL_INSENSITIVE: + return true; + } + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 ) +{ + switch (setType) + { + case ResultSetType::FORWARD_ONLY: + case ResultSetType::SCROLL_INSENSITIVE: + return true; + } + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::ownUpdatesAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::ownDeletesAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::ownInsertsAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::othersUpdatesAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::othersDeletesAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::othersInsertsAreVisible( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::updatesAreDetected( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::deletesAreDetected( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::insertsAreDetected( sal_Int32 ) +{ + return false; +} + +sal_Bool SAL_CALL MacabDatabaseMetaData::supportsBatchUpdates( ) +{ + return false; +} + +Reference< XConnection > SAL_CALL MacabDatabaseMetaData::getConnection( ) +{ + return m_xConnection.get(); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTableTypes( ) +{ + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes); + Reference< XResultSet > xRef = pResult; + + static ODatabaseMetaDataResultSet::ORows aRows = [&] + { + static const char aTable[] = "TABLE"; + ODatabaseMetaDataResultSet::ORows tmp; + ODatabaseMetaDataResultSet::ORow aRow(2); + aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[1] = new ORowSetValueDecorator(OUString(aTable)); + tmp.push_back(aRow); + return tmp; + }(); + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTypeInfo( ) +{ + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo); + Reference< XResultSet > xRef = pResult; + + static ODatabaseMetaDataResultSet::ORows aRows = [&]() + { + ODatabaseMetaDataResultSet::ORows tmp; + ODatabaseMetaDataResultSet::ORow aRow(19); + + // We support four types: char, timestamp, integer, float + aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[1] = new ORowSetValueDecorator(OUString("CHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::CHAR); + aRow[3] = new ORowSetValueDecorator(sal_Int32(254)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[6] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[7] = new ORowSetValueDecorator(sal_Int32(ColumnValue::NULLABLE)); + aRow[8] = ODatabaseMetaDataResultSet::get1Value(); + aRow[9] = new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR)); + aRow[10] = ODatabaseMetaDataResultSet::get1Value(); + aRow[11] = ODatabaseMetaDataResultSet::get0Value(); + aRow[12] = ODatabaseMetaDataResultSet::get0Value(); + aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[14] = ODatabaseMetaDataResultSet::get0Value(); + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); + aRow[16] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[17] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[18] = new ORowSetValueDecorator(sal_Int32(10)); + + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP")); + aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP); + aRow[3] = new ORowSetValueDecorator(sal_Int32(19)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("INTEGER")); + aRow[2] = new ORowSetValueDecorator(DataType::INTEGER); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[15] = new ORowSetValueDecorator(sal_Int32(20)); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("FLOAT")); + aRow[2] = new ORowSetValueDecorator(DataType::FLOAT); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[15] = new ORowSetValueDecorator(sal_Int32(15)); + tmp.push_back(aRow); + + return tmp; + }(); + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getCatalogs( ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCatalogs ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getSchemas( ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eSchemas ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getColumnPrivileges( + const Any&, const OUString&, const OUString&, + const OUString& ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumnPrivileges ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getColumns( + const Any&, + const OUString&, + const OUString& tableNamePattern, + const OUString& columnNamePattern) +{ + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns); + Reference< XResultSet > xRef = pResult; + MacabRecords *aRecords; + OUString sTableName; + + aRecords = m_xConnection->getAddressBook()->getMacabRecordsMatch(tableNamePattern); + + ODatabaseMetaDataResultSet::ORows aRows; + if(aRecords != nullptr) + { + MacabHeader *aHeader = aRecords->getHeader(); + sTableName = aRecords->getName(); + + ODatabaseMetaDataResultSet::ORow aRow(19); + + aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[2] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[3] = new ORowSetValueDecorator(sTableName); + aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[9] = ODatabaseMetaDataResultSet::get0Value(); + aRow[10] = new ORowSetValueDecorator(sal_Int32(10)); + aRow[11] = ODatabaseMetaDataResultSet::get1Value(); + aRow[12] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[14] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[15] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[16] = new ORowSetValueDecorator(sal_Int32(254)); + aRow[18] = new ORowSetValueDecorator(OUString("YES")); + + sal_Int32 nPosition = 1; + OUString sName; + + MacabHeader::iterator aField; + + for ( aField = aHeader->begin(); + aField != aHeader->end(); + ++aField, ++nPosition) + { + + sName = CFStringToOUString(static_cast<CFStringRef>((*aField)->value)); + if (match(columnNamePattern, sName, '\0')) + { + aRow[4] = new ORowSetValueDecorator(sName); + aRow[17] = new ORowSetValueDecorator(nPosition); + switch((*aField)->type) + { + case kABStringProperty: + aRow[5] = new ORowSetValueDecorator(DataType::CHAR); + aRow[6] = new ORowSetValueDecorator(OUString("CHAR")); + aRow[7] = new ORowSetValueDecorator(sal_Int32(256)); + aRows.push_back(aRow); + break; + case kABDateProperty: + aRow[5] = new ORowSetValueDecorator(DataType::TIMESTAMP); + aRow[6] = new ORowSetValueDecorator(OUString("TIMESTAMP")); + aRows.push_back(aRow); + break; + case kABIntegerProperty: + aRow[5] = new ORowSetValueDecorator(DataType::INTEGER); + aRow[6] = new ORowSetValueDecorator(OUString("INTEGER")); + aRow[7] = new ORowSetValueDecorator(sal_Int32(20)); + aRows.push_back(aRow); + break; + case kABRealProperty: + aRow[5] = new ORowSetValueDecorator(DataType::FLOAT); + aRow[6] = new ORowSetValueDecorator(OUString("FLOAT")); + aRow[7] = new ORowSetValueDecorator(sal_Int32(15)); + aRows.push_back(aRow); + break; + default: + ; + // shouldn't happen -- throw an error...? + } + } + } + } + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTables( + const Any&, + const OUString&, + const OUString&, + const Sequence< OUString >& types) +{ + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTables); + Reference< XResultSet > xRef = pResult; + + // check whether we have tables in the requested types + // for the moment, we answer only the "TABLE" table type + // when no types are given at all, we return all the tables + static const char aTable[] = "TABLE"; + bool bTableFound = false; + const OUString* p = types.getConstArray(), + * pEnd = p + types.getLength(); + + if (p == pEnd) + { + bTableFound = true; + } + else while (p < pEnd) + { + if (match(*p, aTable, '\0')) + { + bTableFound = true; + break; + } + p++; + } + if (!bTableFound) + return xRef; + + static ODatabaseMetaDataResultSet::ORows aRows = [&]() + { + ODatabaseMetaDataResultSet::ORows tmp; + ODatabaseMetaDataResultSet::ORow aRow(6); + + MacabRecords *xRecords = m_xConnection->getAddressBook()->getMacabRecords(); + std::vector<MacabGroup *> xGroups = m_xConnection->getAddressBook()->getMacabGroups(); + sal_Int32 i, nGroups; + nGroups = xGroups.size(); + + aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[2] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[3] = new ORowSetValueDecorator(xRecords->getName()); + aRow[4] = new ORowSetValueDecorator(OUString(aTable)); + aRow[5] = ODatabaseMetaDataResultSet::getEmptyValue(); + tmp.push_back(aRow); + + for(i = 0; i < nGroups; i++) + { + aRow[3] = new ORowSetValueDecorator(xGroups[i]->getName()); + tmp.push_back(aRow); + } + return tmp; + }(); + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getProcedureColumns( + const Any&, const OUString&, + const OUString&, const OUString& ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedureColumns ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getProcedures( + const Any&, const OUString&, + const OUString& ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eProcedures ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getVersionColumns( + const Any&, const OUString&, const OUString& table ) +{ + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eVersionColumns); + Reference< XResultSet > xRef = pResult; + + ODatabaseMetaDataResultSet::ORows aRows; + + if (m_xConnection->getAddressBook()->getMacabRecords(table) != nullptr) + { + ODatabaseMetaDataResultSet::ORow aRow( 9 ); + + OUString sName = CFStringToOUString(kABModificationDateProperty); + + aRow[0] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[1] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[2] = new ORowSetValueDecorator(sName); + aRow[3] = new ORowSetValueDecorator(DataType::TIMESTAMP); + aRow[4] = new ORowSetValueDecorator(OUString("TIMESTAMP")); + + aRow[5] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[6] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[7] = ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue(); + + aRows.push_back(aRow); + } + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getExportedKeys( + const Any&, const OUString&, const OUString& ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eExportedKeys ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getImportedKeys( + const Any&, const OUString&, const OUString& ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eImportedKeys ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getPrimaryKeys( + const Any&, const OUString&, const OUString& ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::ePrimaryKeys ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getIndexInfo( + const Any&, const OUString&, const OUString&, + sal_Bool, sal_Bool ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eIndexInfo ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getBestRowIdentifier( + const Any&, const OUString&, const OUString&, sal_Int32, + sal_Bool ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eBestRowIdentifier ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTablePrivileges( + const Any&, const OUString&, const OUString& ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getCrossReference( + const Any&, const OUString&, + const OUString&, const Any&, + const OUString&, const OUString& ) +{ + return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eCrossReference ); +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getUDTs( const Any&, const OUString&, const OUString&, const Sequence< sal_Int32 >& ) +{ + OSL_FAIL("Not implemented yet!"); + throw SQLException(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx b/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx new file mode 100644 index 000000000..c1c9feb5c --- /dev/null +++ b/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx @@ -0,0 +1,201 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABDATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABDATABASEMETADATA_HXX + +#include "MacabConnection.hxx" +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity +{ + namespace macab + { + + class MacabDatabaseMetaData : public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData> + { + rtl::Reference< MacabConnection > m_xConnection; + bool m_bUseCatalog; + + public: + + MacabConnection* getOwnConnection() const { return m_xConnection.get(); } + + explicit MacabDatabaseMetaData(MacabConnection* _pCon); + virtual ~MacabDatabaseMetaData() override; + + // this interface is really BIG + // XDatabaseMetaData + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override; + virtual OUString SAL_CALL getIdentifierQuoteString( ) override; + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL isCatalogAtStart( ) override; + virtual OUString SAL_CALL getCatalogSeparator( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxStatements( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABDATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabDriver.cxx b/connectivity/source/drivers/macab/MacabDriver.cxx new file mode 100644 index 000000000..7a130f364 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabDriver.cxx @@ -0,0 +1,322 @@ +/* -*- 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 "MacabDriver.hxx" +#include "MacabConnection.hxx" + +#include <com/sun/star/sdb/SQLContext.hpp> +#include <com/sun/star/lang/NullPointerException.hpp> +#include <com/sun/star/frame/Desktop.hpp> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> +#include <strings.hrc> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/supportsservice.hxx> + +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::sdb; +using namespace com::sun::star::frame; +using namespace connectivity::macab; + +namespace { + +/** throws a generic SQL exception with SQLState S1000 and error code 0 + */ +void throwGenericSQLException( const OUString& _rMessage ) +{ + SQLException aError; + aError.Message = _rMessage; + aError.SQLState = "S1000"; + aError.ErrorCode = 0; + throw aError; +} + +/** throws an SQLException saying that no Mac OS installation was found + */ +void throwNoMacOSException() +{ + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString( + STR_NO_MAC_OS_FOUND + ) ); + throwGenericSQLException( sError ); +} + + +} + +// = MacabImplModule + + +MacabImplModule::MacabImplModule() + :m_bAttemptedLoadModule(false) + ,m_hConnectorModule(nullptr) + ,m_pConnectionFactoryFunc(nullptr) +{ +} + + +bool MacabImplModule::isMacOSPresent() +{ + return impl_loadModule(); +} + + +namespace +{ + template< typename FUNCTION > + void lcl_getFunctionFromModuleOrUnload( oslModule& _rModule, const char* _pAsciiSymbolName, FUNCTION& _rFunction ) + { + _rFunction = nullptr; + if ( _rModule ) + { + + const OUString sSymbolName = OUString::createFromAscii( _pAsciiSymbolName ); + _rFunction = reinterpret_cast<FUNCTION>( osl_getSymbol( _rModule, sSymbolName.pData ) ); + + if ( !_rFunction ) + { // did not find the symbol + SAL_WARN( "connectivity.macab", "lcl_getFunctionFromModuleOrUnload: could not find the symbol " << _pAsciiSymbolName ); + osl_unloadModule( _rModule ); + _rModule = nullptr; + } + } + } +} + + +extern "C" { static void thisModule() {} } + +bool MacabImplModule::impl_loadModule() +{ + if ( m_bAttemptedLoadModule ) + return ( m_hConnectorModule != nullptr ); + m_bAttemptedLoadModule = true; + + OSL_ENSURE( !m_hConnectorModule && !m_pConnectionFactoryFunc, + "MacabImplModule::impl_loadModule: inconsistence: inconsistency (never attempted load before, but some values already set)!"); + + const OUString sModuleName( SAL_MODULENAME( "macabdrv1" ) ); + m_hConnectorModule = osl_loadModuleRelative( &thisModule, sModuleName.pData, SAL_LOADMODULE_NOW ); // LAZY! #i61335# + OSL_ENSURE( m_hConnectorModule, "MacabImplModule::impl_loadModule: could not load the implementation library!" ); + if ( !m_hConnectorModule ) + return false; + + lcl_getFunctionFromModuleOrUnload( m_hConnectorModule, "createMacabConnection", m_pConnectionFactoryFunc ); + + if ( !m_hConnectorModule ) + // one of the symbols did not exist + throw RuntimeException(); + + return true; +} + + +void MacabImplModule::impl_unloadModule() +{ + OSL_PRECOND( m_hConnectorModule != nullptr, "MacabImplModule::impl_unloadModule: no module!" ); + + osl_unloadModule( m_hConnectorModule ); + m_hConnectorModule = nullptr; + + m_pConnectionFactoryFunc = nullptr; + + m_bAttemptedLoadModule = false; +} + + +void MacabImplModule::init() +{ + if ( !impl_loadModule() ) + throwNoMacOSException(); + +} + + +MacabConnection* MacabImplModule::createConnection( MacabDriver* _pDriver ) const +{ + OSL_PRECOND( m_hConnectorModule, "MacabImplModule::createConnection: not initialized!" ); + + void* pUntypedConnection = (*m_pConnectionFactoryFunc)( _pDriver ); + if ( !pUntypedConnection ) + throw RuntimeException(); + + return static_cast< MacabConnection* >( pUntypedConnection ); +} + + +void MacabImplModule::shutdown() +{ + if ( !m_hConnectorModule ) + return; + + impl_unloadModule(); +} + + +// = MacabDriver + +MacabDriver::MacabDriver( + const Reference< css::uno::XComponentContext >& _rxContext) + : MacabDriver_BASE(m_aMutex), + m_xContext(_rxContext), + m_aImplModule() +{ + if ( !m_xContext.is() ) + throw NullPointerException(); + + osl_atomic_increment( &m_refCount ); + try + { + Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext ); + xDesktop->addTerminateListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.macab"); + } + osl_atomic_decrement( &m_refCount ); +} + +void MacabDriver::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + // when driver will be destroyed so all our connections have to be destroyed as well + for (auto& rxConnection : m_xConnections) + { + Reference< XComponent > xComp(rxConnection.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + } + m_xConnections.clear(); + + WeakComponentImplHelperBase::disposing(); +} +// static ServiceInfo + +OUString MacabDriver::getImplementationName_Static( ) +{ + return "com.sun.star.comp.sdbc.macab.Driver"; +} + +Sequence< OUString > MacabDriver::getSupportedServiceNames_Static( ) +{ + // which service is supported + // for more information @see com.sun.star.sdbc.Driver + Sequence<OUString> aSNS { "com.sun.star.sdbc.Driver" }; + + return aSNS; +} + +OUString SAL_CALL MacabDriver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL MacabDriver::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > SAL_CALL MacabDriver::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + +Reference< XConnection > SAL_CALL MacabDriver::connect( const OUString& url, const Sequence< PropertyValue >& info ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + m_aImplModule.init(); + + // create a new connection with the given properties and append it to our vector + MacabConnection* pConnection = m_aImplModule.createConnection( this ); + SAL_WARN_IF( !pConnection, "connectivity.macab", "MacabDriver::connect: no connection has been created by the factory!" ); + + // by definition, the factory function returned an object which was acquired once + Reference< XConnection > xConnection = pConnection; + pConnection->release(); + + // late constructor call which can throw exception and allows a correct dtor call when so + pConnection->construct( url, info ); + + // remember it + m_xConnections.push_back( WeakReferenceHelper( *pConnection ) ); + + return xConnection; +} + +sal_Bool SAL_CALL MacabDriver::acceptsURL( const OUString& url ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + if ( !m_aImplModule.isMacOSPresent() ) + return false; + + // here we have to look whether we support this URL format + return url == "sdbc:address:macab"; +} + +Sequence< DriverPropertyInfo > SAL_CALL MacabDriver::getPropertyInfo( const OUString&, const Sequence< PropertyValue >& ) +{ + // if you have something special to say, return it here :-) + return Sequence< DriverPropertyInfo >(); +} + +sal_Int32 SAL_CALL MacabDriver::getMajorVersion( ) +{ + return MACAB_DRIVER_VERSION_MAJOR; +} + +sal_Int32 SAL_CALL MacabDriver::getMinorVersion( ) +{ + return MACAB_DRIVER_VERSION_MINOR; +} + +void SAL_CALL MacabDriver::queryTermination( const EventObject& ) +{ + // nothing to do, nothing to veto +} + +void SAL_CALL MacabDriver::notifyTermination( const EventObject& ) +{ + m_aImplModule.shutdown(); +} + +void SAL_CALL MacabDriver::disposing( const EventObject& ) +{ + // not interested in (this is the disposing of the desktop, if any) +} + +OUString MacabDriver::impl_getConfigurationSettingsPath() +{ + return "/org.openoffice.Office.DataAccess/DriverSettings/com.sun.star.comp.sdbc.macab.Driver"; +} + +Reference< XInterface > MacabDriver::Create( const Reference< XMultiServiceFactory >& _rxFactory ) +{ + return *(new MacabDriver(comphelper::getComponentContext(_rxFactory))); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabDriver.hxx b/connectivity/source/drivers/macab/MacabDriver.hxx new file mode 100644 index 000000000..0d389712f --- /dev/null +++ b/connectivity/source/drivers/macab/MacabDriver.hxx @@ -0,0 +1,177 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABDRIVER_HXX + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/compbase.hxx> +#include <osl/module.h> + +// the address book driver's version +#define MACAB_DRIVER_VERSION "0.1" +#define MACAB_DRIVER_VERSION_MAJOR 0 +#define MACAB_DRIVER_VERSION_MINOR 1 + +namespace connectivity +{ + namespace macab + { + class MacabConnection; + class MacabDriver; + + typedef void* (SAL_CALL * ConnectionFactoryFunction)( void* _pDriver ); + + typedef std::vector< css::uno::WeakReferenceHelper > OWeakRefArray; + + + // = MacabImplModule + + class MacabImplModule + { + private: + /// Did we already attempt to load the module and to retrieve the symbols? + bool m_bAttemptedLoadModule; + oslModule m_hConnectorModule; + ConnectionFactoryFunction m_pConnectionFactoryFunc; + + public: + MacabImplModule(); + + /** determines whether there is a mac OS present in the environment + */ + bool isMacOSPresent(); + + /** initializes the implementation module. + + @throws css::uno::RuntimeException + if the module could be loaded, but required symbols are missing + @throws css::sdbc::SQLException + if no Mac OS was found at all + */ + void init(); + + /** shuts down the impl module + */ + void shutdown(); + + /** creates a new connection + @precond + <member>init</member> has been called before + @throws css::uno::RuntimeException + if no connection object could be created (which is a severe error, normally impossible) + */ + MacabConnection* createConnection( MacabDriver* _pDriver ) const; + + private: + /** loads the implementation module and retrieves the needed symbols + + Save against being called multiple times. + + @return <TRUE/> if the module could be loaded successfully. + + @throws css::uno::RuntimeException + if the module could be loaded, but required symbols are missing + */ + bool impl_loadModule(); + + /** unloads the implementation module, and resets all function pointers to <NULL/> + @precond m_hConnectorModule is not <NULL/> + */ + void impl_unloadModule(); + }; + + + // = MacabDriver + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver, + css::lang::XServiceInfo, + css::frame::XTerminateListener > MacabDriver_BASE; + class MacabDriver : public MacabDriver_BASE + { + protected: + ::osl::Mutex m_aMutex; // mutex is need to control member access + OWeakRefArray m_xConnections; // vector containing a list of all the + // MacabConnection objects for this Driver + css::uno::Reference< css::uno::XComponentContext > + m_xContext; // the multi-service factory + MacabImplModule m_aImplModule; + + public: + /// @throws css::uno::Exception + static css::uno::Reference< css::uno::XInterface > Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + // XServiceInfo - static versions + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + css::uno::Reference< css::uno::XComponentContext > const & + getComponentContext() const { return m_xContext; } + + /** returns the path of our configuration settings + */ + static OUString impl_getConfigurationSettingsPath(); + + protected: + explicit MacabDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion() override; + virtual sal_Int32 SAL_CALL getMinorVersion() override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + /** shuts down the library which contains the real implementations + + This method is safe against being called multiple times + + @precond our mutex is locked + */ + void impl_shutdownImplementationModule(); + }; + } + +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABDRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabGroup.cxx b/connectivity/source/drivers/macab/MacabGroup.cxx new file mode 100644 index 000000000..a57f1729f --- /dev/null +++ b/connectivity/source/drivers/macab/MacabGroup.cxx @@ -0,0 +1,93 @@ +/* -*- 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 "MacabGroup.hxx" +#include "MacabRecords.hxx" +#include "macabutilities.hxx" + +using namespace connectivity::macab; + + +/* A MacabGroup is basically a MacabRecords with a different constructor. + * It only exists as a different entity for clarification purposes (a group + * is its own entity in the macOS Address Book) and because its + * construction is so unique (it is based on an already existent + * MacabRecords of the entire address book). + */ +MacabGroup::MacabGroup(const ABAddressBookRef _addressBook, const MacabRecords *_allRecords, const ABGroupRef _xGroup) + : MacabRecords(_addressBook) +{ + sal_Int32 i, j, nAllRecordsSize; + CFArrayRef xGroupMembers = ABGroupCopyArrayOfAllMembers(_xGroup); + ABPersonRef xPerson; + CFStringRef sGroupMemberUID; + bool bFound; + macabfield *xRecordField; + + // Set the group's name (stored in MacabRecords as m_sName) + CFStringRef sGroupName; + sGroupName = static_cast<CFStringRef>(ABRecordCopyValue(_xGroup, kABGroupNameProperty)); + m_sName = CFStringToOUString(sGroupName); + CFRelease(sGroupName); + + // The _group's_ records (remember MacabGroup inherits from MacabRecords) + recordsSize = static_cast<sal_Int32>(CFArrayGetCount(xGroupMembers)); + records = new MacabRecord *[recordsSize]; + setHeader(_allRecords->getHeader()); + + /* Go through each record in the group and try to find that record's UID + * in the MacabRecords that was passed in. If it is found, add that + * record to the group. Otherwise, report an error. (All records should + * exist in the MacabRecords that was passed in.) + */ + nAllRecordsSize = _allRecords->size(); + for(i = 0; i < recordsSize; i++) + { + xPerson = static_cast<ABPersonRef>(const_cast<void *>(CFArrayGetValueAtIndex(xGroupMembers,i))); + if(xPerson != nullptr) + { + sGroupMemberUID = static_cast<CFStringRef>(ABRecordCopyValue(xPerson, kABUIDProperty)); + if(sGroupMemberUID != nullptr) + { + bFound = false; + for(j = 0; j < nAllRecordsSize; j++) + { + xRecordField = _allRecords->getField(j,CFStringToOUString(kABUIDProperty)); + if(xRecordField != nullptr && xRecordField->value != nullptr) + { + if(CFEqual(xRecordField->value, sGroupMemberUID)) + { + /* Found the matching UID! Insert into the group... */ + insertRecord(_allRecords->getRecord(j)); + bFound = true; + break; + } + } + } + OSL_ENSURE(bFound, "MacabGroup::MacabGroup : Could not find group member based on UID!"); + CFRelease(sGroupMemberUID); + } + } + } + + CFRelease(xGroupMembers); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabGroup.hxx b/connectivity/source/drivers/macab/MacabGroup.hxx new file mode 100644 index 000000000..4d9313282 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabGroup.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABGROUP_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABGROUP_HXX + +#include "MacabRecords.hxx" + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> + + +namespace connectivity +{ + namespace macab + { + class MacabGroup: public MacabRecords { + public: + MacabGroup(const ABAddressBookRef _addressBook, const MacabRecords *_allRecords, const ABGroupRef _xGroup); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABGROUP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabHeader.cxx b/connectivity/source/drivers/macab/MacabHeader.cxx new file mode 100644 index 000000000..dc83d9c3d --- /dev/null +++ b/connectivity/source/drivers/macab/MacabHeader.cxx @@ -0,0 +1,334 @@ +/* -*- 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 "MacabHeader.hxx" +#include "MacabRecord.hxx" +#include "macabutilities.hxx" + +#include <math.h> +#include <com/sun/star/sdbc/DataType.hpp> +#include <connectivity/dbconversion.hxx> + +using namespace connectivity::macab; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::util; +using namespace ::dbtools; + + +MacabHeader::MacabHeader(const sal_Int32 _size, macabfield **_fields) +{ + sal_Int32 i; + size = _size; + fields = std::make_unique<macabfield *[]>(size); + for(i = 0; i < size; i++) + { + if(_fields[i] == nullptr) + { + fields[i] = nullptr; + } + else + { + /* The constructor duplicates the macabfields it gets because they + * are either deleted later or used for other purposes. + */ + fields[i] = new macabfield; + fields[i]->type = _fields[i]->type; + fields[i]->value = _fields[i]->value; + if (fields[i]->value) + CFRetain(fields[i]->value); + } + } + +} + + +MacabHeader::MacabHeader() +{ + size = 0; + fields = nullptr; +} + + +MacabHeader::~MacabHeader() +{ +} + + +void MacabHeader::operator+= (const MacabHeader *r) +{ + /* Add one MacabHeader to another. Anything not already in the header is + * added to the end of it. + */ + sal_Int32 rSize = r->getSize(); + if(rSize != 0) // If the new header does actually have fields + { + /* If our header is currently empty, just copy all of the fields from + * the new header to this one. + */ + if(size == 0) + { + sal_Int32 i; + size = rSize; + fields = std::make_unique<macabfield *[]>(size); + for(i = 0; i < size; i++) + { + fields[i] = r->copy(i); + } + } + + /* Otherwise, only add the duplicates. We do this with a two-pass + * approach. First, find out how many fields to add, then reallocate + * the size of the fields array and add the old ones at the end. + * (More precisely, we create a _new_ fields array with the new length + * allocated to it, then get all of the fields from the current + * fields array to it, then copy the non-duplicates from the new + * header to the end.) + */ + else + { + sal_Int32 i; + sal_Int32 numToAdd = 0, numAdded = 0; + macabfield **newFields; + for( i = 0; i < rSize; i++) + { + if(!contains(r->get(i))) + { + numToAdd++; + } + } + + newFields = new macabfield *[size+numToAdd]; + for(i = 0; i < size; i++) + { + newFields[i] = copy(i); + } + + for( i = 0; i < rSize; i++) + { + if(!contains(r->get(i))) + { + newFields[size+numAdded] = r->copy(i); + numAdded++; + if(numAdded == numToAdd) + break; + } + } + + releaseFields(); + size += numAdded; + fields.reset(newFields); + } + } +} + + +OUString MacabHeader::getString(const sal_Int32 i) const +{ + OUString nRet; + + if(i < size) + { + if(fields[i] == nullptr || fields[i]->value == nullptr || CFGetTypeID(fields[i]->value) != CFStringGetTypeID()) + return OUString(); + try + { + nRet = CFStringToOUString(static_cast<CFStringRef>(fields[i]->value)); + } + catch(...){ } + } + + return nRet; +} + + +void MacabHeader::sortRecord() +{ + sortRecord(0,size); +} + + +macabfield **MacabHeader::sortRecord(const sal_Int32 _start, const sal_Int32 _length) +{ + /* Sort using mergesort. Because it uses mergesort, it is recursive and + * not in place (so it creates a new array at every step of the + * recursion), so if you prefer to use a different sort, please feel + * free to implement it. + */ + macabfield** sorted = new macabfield *[_length]; + if(_length <= 2) + { + if(_length == 2) + { + if(compareFields(fields[_start], fields[_start+1]) > 0) + { + sorted[0] = get(_start+1); + sorted[1] = get(_start); + } + else + { + sorted[0] = get(_start); + sorted[1] = get(_start+1); + } + } + else if(_length == 1) + { + sorted[0] = get(_start); + } + } + else + { + sal_Int32 halfLength = floor(_length/2); + sal_Int32 fp = 0, lp = 0; + sal_Int32 i; + macabfield **firstHalf = sortRecord(_start, halfLength); + macabfield **lastHalf = sortRecord(_start+halfLength, _length-halfLength); + + for(i = 0; i < _length; i++) + { + if(compareFields(firstHalf[fp],lastHalf[lp]) < 0) + { + sorted[i] = firstHalf[fp++]; + if(fp == halfLength) + { + for( i++; i < _length; i++) + { + sorted[i] = lastHalf[lp++]; + } + break; + } + } + else + { + sorted[i] = lastHalf[lp++]; + if(lp == _length - halfLength) + { + for( i++; i < _length; i++) + { + sorted[i] = firstHalf[fp++]; + } + break; + } + } + } + if(_length == size) + { + fields.reset(sorted); + } + delete firstHalf; + delete lastHalf; + } + return sorted; +} + +sal_Int32 MacabHeader::compareFields(const macabfield *_field1, const macabfield *_field2) +{ + /* Comparing two fields in a MacabHeader is different than comparing two + * fields in a MacabRecord. It starts in the same way (if one of the two + * fields is NULL, it belongs after the other, so it is considered + * "greater"). But, then, all headers are CFStrings, no matter what + * type they claim to be (since they actually hold the expected type for + * the records with that header). That being said, all we have to do is + * the built-in CFStringCompare. + */ + if(_field1 == _field2) + return 0; + if(_field1 == nullptr) + return 1; + if(_field2 == nullptr) + return -1; + + CFComparisonResult result = CFStringCompare( + static_cast<CFStringRef>(_field1->value), + static_cast<CFStringRef>(_field2->value), + 0); // 0 = no options (like ignore case) + + return static_cast<sal_Int32>(result); +} + + +sal_Int32 MacabHeader::getColumnNumber(const OUString& s) const +{ + sal_Int32 i; + for(i = 0; i < size; i++) + { + if(getString(i) == s) + break; + } + + if(i == size) + i = -1; + + return i; +} + + +MacabHeader *MacabHeader::begin() +{ + return this; +} + + +MacabHeader::iterator::iterator () +{ +} + + +MacabHeader::iterator::~iterator () +{ +} + +MacabHeader::iterator& MacabHeader::iterator::operator= (MacabHeader *_record) +{ + id = 0; + record = _record; + return *this; +} + + +void MacabHeader::iterator::operator++ () +{ + id++; +} + + +bool MacabHeader::iterator::operator!= (const sal_Int32 i) const +{ + return(id != i); +} + + +bool MacabHeader::iterator::operator== (const sal_Int32 i) const +{ + return(id == i); +} + + +macabfield *MacabHeader::iterator::operator* () const +{ + return record->get(id); +} + + +sal_Int32 MacabHeader::end() const +{ + return size; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabHeader.hxx b/connectivity/source/drivers/macab/MacabHeader.hxx new file mode 100644 index 000000000..c77ae2da0 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabHeader.hxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABHEADER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABHEADER_HXX + +#include "MacabRecord.hxx" + +namespace connectivity +{ + namespace macab + { + class MacabHeader: public MacabRecord{ + protected: + macabfield **sortRecord(sal_Int32 _start, sal_Int32 _length); + public: + MacabHeader(); + MacabHeader(const sal_Int32 _size, macabfield **_fields); + virtual ~MacabHeader() override; + void operator+= (const MacabHeader *r); + OUString getString(const sal_Int32 i) const; + void sortRecord(); + sal_Int32 getColumnNumber(const OUString& s) const; + + static sal_Int32 compareFields(const macabfield *_field1, const macabfield *_field2); + + MacabHeader *begin(); + sal_Int32 end() const; + class iterator{ + protected: + sal_Int32 id; + MacabHeader *record; + public: + iterator& operator= (MacabHeader *_record); + iterator(); + ~iterator(); + void operator++ (); + bool operator!= (const sal_Int32 i) const; + bool operator== (const sal_Int32 i) const; + macabfield *operator* () const; + }; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABHEADER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabPreparedStatement.cxx b/connectivity/source/drivers/macab/MacabPreparedStatement.cxx new file mode 100644 index 000000000..cbb3dc756 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabPreparedStatement.cxx @@ -0,0 +1,343 @@ +/* -*- 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 "MacabPreparedStatement.hxx" +#include "MacabAddressBook.hxx" +#include <propertyids.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbtools.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + +using namespace connectivity::macab; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::util; + +IMPLEMENT_SERVICE_INFO(MacabPreparedStatement, "com.sun.star.sdbc.drivers.MacabPreparedStatement", "com.sun.star.sdbc.PreparedStatement"); + +void MacabPreparedStatement::checkAndResizeParameters(sal_Int32 nParams) +{ + if ( !m_aParameterRow.is() ) + m_aParameterRow = new OValueVector(); + + if (nParams < 1) + ::dbtools::throwInvalidIndexException(*this); + + if (nParams >= static_cast<sal_Int32>(m_aParameterRow->size())) + m_aParameterRow->resize(nParams); +} + +void MacabPreparedStatement::setMacabFields() const +{ + ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns + + xColumns = m_aSQLIterator.getSelectColumns(); + if (!xColumns.is()) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString( + STR_INVALID_COLUMN_SELECTION + ) ); + ::dbtools::throwGenericSQLException(sError,nullptr); + } + m_xMetaData->setMacabFields(xColumns); +} + +void MacabPreparedStatement::resetParameters() const +{ + m_nParameterIndex = 0; +} + +void MacabPreparedStatement::getNextParameter(OUString &rParameter) const +{ + if (m_nParameterIndex >= static_cast<sal_Int32>(m_aParameterRow->size())) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString( + STR_INVALID_PARA_COUNT + ) ); + ::dbtools::throwGenericSQLException(sError,*const_cast<MacabPreparedStatement *>(this)); + } + + rParameter = (*m_aParameterRow)[m_nParameterIndex]; + + m_nParameterIndex++; +} + +MacabPreparedStatement::MacabPreparedStatement( + MacabConnection* _pConnection, + const OUString& sql) + : MacabPreparedStatement_BASE(_pConnection), + m_sSqlStatement(sql), + m_bPrepared(false), + m_nParameterIndex(0), + m_aParameterRow() +{ + +} + +MacabPreparedStatement::~MacabPreparedStatement() +{ +} + +void MacabPreparedStatement::disposing() +{ + MacabPreparedStatement_BASE::disposing(); + + if (m_aParameterRow.is()) + { + m_aParameterRow->clear(); + m_aParameterRow = nullptr; + } +} + +Reference< XResultSetMetaData > SAL_CALL MacabPreparedStatement::getMetaData() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); + + if (!m_xMetaData.is()) + { + const OSQLTables& xTabs = m_aSQLIterator.getTables(); + OUString sTableName = MacabAddressBook::getDefaultTableName(); + + if(! xTabs.empty() ) + { + + // can only deal with one table at a time + if(xTabs.size() == 1 && !m_aSQLIterator.hasErrors() ) + sTableName = xTabs.begin()->first; + + } + m_xMetaData = new MacabResultSetMetaData(getOwnConnection(),sTableName); + setMacabFields(); + } + Reference< XResultSetMetaData > xMetaData = m_xMetaData.get(); + return xMetaData; +} + +void SAL_CALL MacabPreparedStatement::close() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); + + // Reset last warning message + try { + clearWarnings (); + MacabCommonStatement::close(); + } + catch (SQLException &) { + // If we get an error, ignore + } + + // Remove this Statement object from the Connection object's + // list +} + +sal_Bool SAL_CALL MacabPreparedStatement::execute() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); + + Reference< XResultSet> xRS = MacabCommonStatement::executeQuery(m_sSqlStatement); + + return xRS.is(); +} + +sal_Int32 SAL_CALL MacabPreparedStatement::executeUpdate() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); + + // same as in statement with the difference that this statement also can contain parameter + return 0; +} + +Reference< XConnection > SAL_CALL MacabPreparedStatement::getConnection() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); + + return m_pConnection; +} + +Reference< XResultSet > SAL_CALL MacabPreparedStatement::executeQuery() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); + + Reference< XResultSet > rs = MacabCommonStatement::executeQuery(m_sSqlStatement); + + return rs; +} + +void SAL_CALL MacabPreparedStatement::setNull(sal_Int32 parameterIndex, sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); + + checkAndResizeParameters(parameterIndex); + + (*m_aParameterRow)[parameterIndex - 1].setNull(); +} + +void SAL_CALL MacabPreparedStatement::setObjectNull(sal_Int32, sal_Int32, const OUString&) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setObjectNull", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setBoolean(sal_Int32, sal_Bool) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setBoolean", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setByte(sal_Int32, sal_Int8) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setByte", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setShort(sal_Int32, sal_Int16) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setShort", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setInt(sal_Int32, sal_Int32) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setInt", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setLong(sal_Int32, sal_Int64) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setLong", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setFloat(sal_Int32, float) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setFloat", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setDouble(sal_Int32, double) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setDouble", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setString(sal_Int32 parameterIndex, const OUString &x) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabCommonStatement_BASE::rBHelper.bDisposed); + + checkAndResizeParameters(parameterIndex); + + (*m_aParameterRow)[parameterIndex - 1] = x; +} + +void SAL_CALL MacabPreparedStatement::setBytes(sal_Int32, const Sequence< sal_Int8 >&) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setBytes", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setDate(sal_Int32, const Date&) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setDate", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setTime(sal_Int32, const css::util::Time&) +{ + + ::dbtools::throwFunctionNotSupportedSQLException("setTime", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setTimestamp(sal_Int32, const DateTime&) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setTimestamp", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setBinaryStream(sal_Int32, const Reference< css::io::XInputStream >&, sal_Int32) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setBinaryStream", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setCharacterStream(sal_Int32, const Reference< css::io::XInputStream >&, sal_Int32) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setCharacterStream", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setObject(sal_Int32 parameterIndex, const Any& x) +{ + if(!::dbtools::implSetObject(this,parameterIndex,x)) + { + const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution( + STR_UNKNOWN_PARA_TYPE, + "$position$", OUString::number(parameterIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } +} + +void SAL_CALL MacabPreparedStatement::setObjectWithInfo(sal_Int32, const Any&, sal_Int32, sal_Int32) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setObjectWithInfo", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setRef(sal_Int32, const Reference< XRef >&) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setRef", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setBlob(sal_Int32, const Reference< XBlob >&) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setBlob", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setClob(sal_Int32, const Reference< XClob >&) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setClob", nullptr); +} + +void SAL_CALL MacabPreparedStatement::setArray(sal_Int32, const Reference< XArray >&) +{ + ::dbtools::throwFunctionNotSupportedSQLException("setArray", nullptr); +} + +void SAL_CALL MacabPreparedStatement::clearParameters() +{ + ::dbtools::throwFunctionNotSupportedSQLException("clearParameters", nullptr); +} + +void MacabPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + switch (nHandle) + { + case PROPERTY_ID_RESULTSETCONCURRENCY: + break; + case PROPERTY_ID_RESULTSETTYPE: + break; + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_USEBOOKMARKS: + break; + default: + MacabCommonStatement::setFastPropertyValue_NoBroadcast(nHandle,rValue); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabPreparedStatement.hxx b/connectivity/source/drivers/macab/MacabPreparedStatement.hxx new file mode 100644 index 000000000..a37c1b29a --- /dev/null +++ b/connectivity/source/drivers/macab/MacabPreparedStatement.hxx @@ -0,0 +1,117 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABPREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABPREPAREDSTATEMENT_HXX + +#include "MacabStatement.hxx" +#include "MacabResultSetMetaData.hxx" +#include <connectivity/FValue.hxx> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity +{ + namespace macab + { + typedef ::cppu::ImplInheritanceHelper< MacabCommonStatement, + css::sdbc::XPreparedStatement, + css::sdbc::XParameters, + css::sdbc::XResultSetMetaDataSupplier, + css::lang::XServiceInfo> MacabPreparedStatement_BASE; + + class MacabPreparedStatement : public MacabPreparedStatement_BASE + { + protected: + OUString m_sSqlStatement; + ::rtl::Reference< MacabResultSetMetaData > + m_xMetaData; + bool m_bPrepared; + mutable sal_Int32 m_nParameterIndex; + OValueRow m_aParameterRow; + + /// @throws css::sdbc::SQLException + void checkAndResizeParameters(sal_Int32 nParams); + /// @throws css::sdbc::SQLException + void setMacabFields() const; + + protected: + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue) override; + + virtual void resetParameters() const override; + virtual void getNextParameter(OUString &rParameter) const override; + virtual ~MacabPreparedStatement() override; + + public: + DECLARE_SERVICE_INFO(); + MacabPreparedStatement(MacabConnection* _pConnection, const OUString& sql); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XPreparedStatement + using MacabCommonStatement::executeQuery; + using MacabCommonStatement::executeUpdate; + using MacabCommonStatement::execute; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + virtual sal_Bool SAL_CALL execute( ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + + // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + + // XCloseable + virtual void SAL_CALL close( ) override; + + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABPREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabRecord.cxx b/connectivity/source/drivers/macab/MacabRecord.cxx new file mode 100644 index 000000000..3072e1eaa --- /dev/null +++ b/connectivity/source/drivers/macab/MacabRecord.cxx @@ -0,0 +1,336 @@ +/* -*- 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 "MacabRecord.hxx" +#include "macabutilities.hxx" +#include <com/sun/star/util/DateTime.hpp> + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> +#include <connectivity/dbconversion.hxx> + +using namespace connectivity::macab; +using namespace com::sun::star::util; +using namespace ::dbtools; + + +MacabRecord::MacabRecord() : size(0) +{ +} + + +MacabRecord::MacabRecord(const sal_Int32 _size) + : size(_size), + fields(std::make_unique<macabfield *[]>(size)) +{ + sal_Int32 i; + for(i = 0; i < size; i++) + fields[i] = nullptr; +} + + +MacabRecord::~MacabRecord() +{ + if(size > 0) + { + releaseFields(); + int i; + for(i = 0; i < size; i++) + { + delete fields[i]; + fields[i] = nullptr; + } + } +} + + +void MacabRecord::insertAtColumn (CFTypeRef _value, ABPropertyType _type, const sal_Int32 _column) +{ + if(_column < size) + { + if(fields[_column] == nullptr) + fields[_column] = new macabfield; + + fields[_column]->value = _value; + if (fields[_column]->value) + CFRetain(fields[_column]->value); + fields[_column]->type = _type; + } +} + + +bool MacabRecord::contains (const macabfield *_field) const +{ + if(_field == nullptr) + return false; + else + return contains(_field->value); +} + + +bool MacabRecord::contains (const CFTypeRef _value) const +{ + sal_Int32 i; + for(i = 0; i < size; i++) + { + if(fields[i] != nullptr) + { + if(CFEqual(fields[i]->value, _value)) + { + return true; + } + } + } + + return false; +} + + +sal_Int32 MacabRecord::getSize() const +{ + return size; +} + + +macabfield *MacabRecord::copy(const sal_Int32 i) const +{ + /* Note: copy(i) creates a new macabfield identical to that at + * location i, whereas get(i) returns a pointer to the macabfield + * at location i. + */ + if(i < size) + { + macabfield *_copy = new macabfield; + _copy->type = fields[i]->type; + _copy->value = fields[i]->value; + if (_copy->value) + CFRetain(_copy->value); + return _copy; + } + + return nullptr; +} + + +macabfield *MacabRecord::get(const sal_Int32 i) const +{ + /* Note: copy(i) creates a new macabfield identical to that at + * location i, whereas get(i) returns a pointer to the macabfield + * at location i. + */ + if(i < size) + { + return fields[i]; + } + + return nullptr; +} + + +void MacabRecord::releaseFields() +{ + /* This method is, at the moment, only used in MacabHeader.cxx, but + * the idea is simple: if you are not destroying this object but want + * to clear it of its macabfields, you should release each field's + * value. + */ + sal_Int32 i; + for(i = 0; i < size; i++) + CFRelease(fields[i]->value); +} + + +sal_Int32 MacabRecord::compareFields(const macabfield *_field1, const macabfield *_field2) +{ + + /* When comparing records, if either field is NULL (and the other is + * not), that field is considered "greater than" the other, so that it + * shows up later in the list when fields are ordered. + */ + if(_field1 == _field2) + return 0; + if(_field1 == nullptr) + return 1; + if(_field2 == nullptr) + return -1; + + /* If they aren't the same type, for now, return the one with + * the smaller type ID... I don't know of a better way to compare + * two different data types. + */ + if(_field1->type != _field2->type) + return(_field1->type - _field2->type); + + CFComparisonResult result; + + /* Carbon has a unique compare function for each data type: */ + switch(_field1->type) + { + case kABStringProperty: + result = CFStringCompare( + static_cast<CFStringRef>(_field1->value), + static_cast<CFStringRef>(_field2->value), + kCFCompareLocalized); // Specifies that the comparison should take into account differences related to locale, such as the thousands separator character. + break; + + case kABDateProperty: + result = CFDateCompare( + static_cast<CFDateRef>(_field1->value), + static_cast<CFDateRef>(_field2->value), + nullptr); // NULL = unused variable + break; + + case kABIntegerProperty: + case kABRealProperty: + result = CFNumberCompare( + static_cast<CFNumberRef>(_field1->value), + static_cast<CFNumberRef>(_field2->value), + nullptr); // NULL = unused variable + break; + + default: + result = kCFCompareEqualTo; // can't compare + } + + return static_cast<sal_Int32>(result); +} + + +/* Create a macabfield out of an OUString and type. Together with the + * method fieldToString() (below), it is possible to switch conveniently + * between an OUString and a macabfield (for use when creating and handling + * SQL statement). + */ +macabfield *MacabRecord::createMacabField(const OUString& _newFieldString, const ABPropertyType _abType) +{ + macabfield *newField = nullptr; + switch(_abType) + { + case kABStringProperty: + newField = new macabfield; + newField->value = OUStringToCFString(_newFieldString); + newField->type = _abType; + break; + case kABDateProperty: + { + DateTime aDateTime = DBTypeConversion::toDateTime(_newFieldString); + + // bad format... + if(aDateTime.Year == 0 && aDateTime.Month == 0 && aDateTime.Day == 0) + { + } + else + { + double nTime = DBTypeConversion::toDouble(aDateTime, DBTypeConversion::getStandardDate()); + nTime -= kCFAbsoluteTimeIntervalSince1970; + newField = new macabfield; + newField->value = CFDateCreate(nullptr, static_cast<CFAbsoluteTime>(nTime)); + newField->type = _abType; + } + } + break; + case kABIntegerProperty: + try + { + sal_Int64 nVal = _newFieldString.toInt64(); + + newField = new macabfield; + newField->value = CFNumberCreate(nullptr,kCFNumberLongType, &nVal); + newField->type = _abType; + } + // bad format... + catch(...) + { + } + break; + case kABRealProperty: + try + { + double nVal = _newFieldString.toDouble(); + + newField = new macabfield; + newField->value = CFNumberCreate(nullptr,kCFNumberDoubleType, &nVal); + newField->type = _abType; + } + // bad format... + catch(...) + { + } + break; + default: + ; + } + return newField; +} + + +/* Create an OUString out of a macabfield. Together with the method + * createMacabField() (above), it is possible to switch conveniently + * between an OUString and a macabfield (for use when creating and handling + * SQL statement). + */ +OUString MacabRecord::fieldToString(const macabfield *_aField) +{ + if(_aField == nullptr) + return OUString(); + + OUString fieldString; + + switch(_aField->type) + { + case kABStringProperty: + fieldString = CFStringToOUString(static_cast<CFStringRef>(_aField->value)); + break; + case kABDateProperty: + { + DateTime aTime = CFDateToDateTime(static_cast<CFDateRef>(_aField->value)); + fieldString = DBTypeConversion::toDateTimeString(aTime); + } + break; + case kABIntegerProperty: + { + CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(_aField->value) ); + sal_Int64 nVal; + // Should we check for the wrong type here, e.g., a float? + bool m_bSuccess = !CFNumberGetValue(static_cast<CFNumberRef>(_aField->value), numberType, &nVal); + if(m_bSuccess) + fieldString = OUString::number(nVal); + } + break; + case kABRealProperty: + { + CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(_aField->value) ); + double nVal; + // Should we check for the wrong type here, e.g., an int? + bool m_bSuccess = !CFNumberGetValue(static_cast<CFNumberRef>(_aField->value), numberType, &nVal); + if(m_bSuccess) + fieldString = OUString::number(nVal); + } + break; + default: + ; + } + return fieldString; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabRecord.hxx b/connectivity/source/drivers/macab/MacabRecord.hxx new file mode 100644 index 000000000..e677611bd --- /dev/null +++ b/connectivity/source/drivers/macab/MacabRecord.hxx @@ -0,0 +1,77 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRECORD_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRECORD_HXX + +#include <sal/config.h> + +#include <memory> + +#include <sal/types.h> +#include <osl/diagnose.h> +#include <rtl/ustring.hxx> + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> + +namespace connectivity +{ + namespace macab + { + /* a MacabRecord is at root a list of macabfields (which is just + * something to hold both a CFTypeRef (a CoreFoundation object) and + * its Address Book type. + */ + struct macabfield + { + CFTypeRef value; + ABPropertyType type; + }; + + class MacabRecord{ + protected: + sal_Int32 size; + std::unique_ptr<macabfield *[]> fields; + protected: + void releaseFields(); + public: + MacabRecord(); + explicit MacabRecord(const sal_Int32 _size); + virtual ~MacabRecord(); + void insertAtColumn (CFTypeRef _value, ABPropertyType _type, const sal_Int32 _column); + bool contains(const macabfield *_field) const; + bool contains(const CFTypeRef _value) const; + sal_Int32 getSize() const; + macabfield *copy(const sal_Int32 i) const; + macabfield *get(const sal_Int32 i) const; + + static sal_Int32 compareFields(const macabfield *_field1, const macabfield *_field2); + static macabfield *createMacabField(const OUString& _newFieldString, const ABPropertyType _abtype); + static OUString fieldToString(const macabfield *_aField); + + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRECORD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabRecords.cxx b/connectivity/source/drivers/macab/MacabRecords.cxx new file mode 100644 index 000000000..0bc27ea0e --- /dev/null +++ b/connectivity/source/drivers/macab/MacabRecords.cxx @@ -0,0 +1,1164 @@ +/* -*- 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 <memory> +#include <utility> +#include <vector> + +#include "MacabRecords.hxx" +#include "MacabRecord.hxx" +#include "MacabHeader.hxx" +#include "macabutilities.hxx" + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> +#include <com/sun/star/util/DateTime.hpp> + +using namespace connectivity::macab; +using namespace com::sun::star::util; + +namespace { + +void manageDuplicateHeaders(macabfield **_headerNames, const sal_Int32 _length) +{ + /* If we have two cases of, say, phone: home, this makes it: + * phone: home (1) + * phone: home (2) + */ + sal_Int32 i, j; + sal_Int32 count; + for(i = _length-1; i >= 0; i--) + { + count = 1; + for( j = i-1; j >= 0; j--) + { + if(CFEqual(_headerNames[i]->value, _headerNames[j]->value)) + { + count++; + } + } + + // duplicate! + if(count != 1) + { + // There is probably a better way to do this... + OUString newName = CFStringToOUString(static_cast<CFStringRef>(_headerNames[i]->value)); + CFRelease(_headerNames[i]->value); + newName += " (" + OUString::number(count) + ")"; + _headerNames[i]->value = OUStringToCFString(newName); + } + } +} + +} + +MacabRecords::MacabRecords(const ABAddressBookRef _addressBook, MacabHeader *_header, MacabRecord **_records, sal_Int32 _numRecords) + : recordsSize(_numRecords), currentRecord(_numRecords), recordType(kABPersonRecordType), + header(_header), records(_records), addressBook(_addressBook) +{ + /* Variables constructed... */ + bootstrap_CF_types(); + bootstrap_requiredProperties(); +} + + +/* Creates a MacabRecords from another: copies the length, name, and + * address book of the original, but the header or the records themselves. + * The idea is that the only reason to copy a MacabRecords is to create + * a filtered version of it, which can have the same length (to avoid + * resizing) and will work from the same base addressbook, but might have + * entirely different values and even (possibly in the future) a different + * header. + */ +MacabRecords::MacabRecords(const MacabRecords *_copy) + : recordsSize(_copy->recordsSize), currentRecord(0), recordType(kABPersonRecordType), + header(nullptr), records(new MacabRecord *[recordsSize]), addressBook(_copy->addressBook), + m_sName(_copy->m_sName) +{ + /* Variables constructed... */ + bootstrap_CF_types(); + bootstrap_requiredProperties(); +} + + +MacabRecords::MacabRecords(const ABAddressBookRef _addressBook) + : recordsSize(0), currentRecord(0), recordType(kABPersonRecordType), + header(nullptr), records(nullptr), addressBook(_addressBook) +{ + /* Variables constructed... */ + bootstrap_CF_types(); + bootstrap_requiredProperties(); +} + + +void MacabRecords::initialize() +{ + + /* Make sure everything is NULL before initializing. (We usually just + * initialize after we use the constructor that takes only a + * MacabAddressBook, so these variables will most likely already be + * NULL. + */ + if(records != nullptr) + { + sal_Int32 i; + + for(i = 0; i < recordsSize; i++) + delete records[i]; + + delete [] records; + } + + if(header != nullptr) + delete header; + + /* We can handle both default record Address Book record types in + * this method, though only kABPersonRecordType is ever used. + */ + CFArrayRef allRecords; + if(CFStringCompare(recordType, kABPersonRecordType, 0) == kCFCompareEqualTo) + allRecords = ABCopyArrayOfAllPeople(addressBook); + else + allRecords = ABCopyArrayOfAllGroups(addressBook); + + ABRecordRef record; + sal_Int32 i; + recordsSize = static_cast<sal_Int32>(CFArrayGetCount(allRecords)); + records = new MacabRecord *[recordsSize]; + + /* First, we create the header... */ + header = createHeaderForRecordType(allRecords, recordType); + + /* Then, we create each of the records... */ + for(i = 0; i < recordsSize; i++) + { + record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(allRecords, i)); + records[i] = createMacabRecord(record, header, recordType); + } + currentRecord = recordsSize; + + CFRelease(allRecords); +} + + +MacabRecords::~MacabRecords() +{ +} + + +void MacabRecords::setHeader(MacabHeader *_header) +{ + if(header != nullptr) + delete header; + header = _header; +} + + +MacabHeader *MacabRecords::getHeader() const +{ + return header; +} + + +/* Inserts a MacabRecord at a given location. If there is already a + * MacabRecord at that location, return it. + */ +MacabRecord *MacabRecords::insertRecord(MacabRecord *_newRecord, const sal_Int32 _location) +{ + MacabRecord *oldRecord; + + /* If the location is greater than the current allocated size of this + * MacabRecords, allocate more space. + */ + if(_location >= recordsSize) + { + sal_Int32 i; + MacabRecord **newRecordsArray = new MacabRecord *[_location+1]; + for(i = 0; i < recordsSize; i++) + { + newRecordsArray[i] = records[i]; + } + delete [] records; + records = newRecordsArray; + } + + /* Remember: currentRecord refers to one above the highest existing + * record (i.e., it refers to where to place the next record if a + * location is not given). + */ + if(_location >= currentRecord) + currentRecord = _location+1; + + oldRecord = records[_location]; + records[_location] = _newRecord; + return oldRecord; +} + + +/* Insert a record at the next available place. */ +void MacabRecords::insertRecord(MacabRecord *_newRecord) +{ + insertRecord(_newRecord, currentRecord); +} + + +MacabRecord *MacabRecords::getRecord(const sal_Int32 _location) const +{ + if(_location >= recordsSize) + return nullptr; + return records[_location]; +} + + +macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, const sal_Int32 _columnNumber) const +{ + if(_recordNumber >= recordsSize) + return nullptr; + + MacabRecord *record = records[_recordNumber]; + + if(_columnNumber < 0 || _columnNumber >= record->getSize()) + return nullptr; + + return record->get(_columnNumber); +} + + +macabfield *MacabRecords::getField(const sal_Int32 _recordNumber, const OUString& _columnName) const +{ + if(header != nullptr) + { + sal_Int32 columnNumber = header->getColumnNumber(_columnName); + if(columnNumber == -1) + return nullptr; + + return getField(_recordNumber, columnNumber); + } + else + { + // error: shouldn't access field with null header! + return nullptr; + } +} + + +sal_Int32 MacabRecords::getFieldNumber(const OUString& _columnName) const +{ + if(header != nullptr) + return header->getColumnNumber(_columnName); + else + // error: shouldn't access field with null header! + return -1; +} + + +/* Create the lcl_CFTypes array -- we need this because there is no + * way to get the ABType of an object from the object itself, and the + * function ABTypeOfProperty can't handle multiple levels of data + * (e.g., it can tell us that "address" is of type + * kABDictionaryProperty, but it cannot tell us that all of the keys + * and values in the dictionary have type kABStringProperty. On the + * other hand, we _can_ get the CFType out of any object. + * Unfortunately, all information about CFTypeIDs comes with the + * warning that they change between releases, so we build them + * ourselves here. (The one that we can't build is for multivalues, + * e.g., kABMultiStringProperty. All of these appear to have the + * same type: 1, but there is no function that I've found to give + * us that dynamically in case that number ever changes. + */ +void MacabRecords::bootstrap_CF_types() +{ + lcl_CFTypes = { + {CFNumberGetTypeID(), kABIntegerProperty}, + {CFStringGetTypeID(), kABStringProperty}, + {CFDateGetTypeID(), kABDateProperty}, + {CFArrayGetTypeID(), kABArrayProperty}, + {CFDictionaryGetTypeID(), kABDictionaryProperty}, + {CFDataGetTypeID(), kABDataProperty}}; +} + + +/* This is based on the possible fields required in the mail merge template + * in sw. If the fields possible there change, it would be optimal to + * change these fields as well. + */ +void MacabRecords::bootstrap_requiredProperties() +{ + requiredProperties = { + kABTitleProperty, kABFirstNameProperty, kABLastNameProperty, kABOrganizationProperty, + kABAddressProperty, kABPhoneProperty, kABEmailProperty}; +} + + +/* Create the header for a given record type and a given array of records. + * Because the array of records and the record type are given, if you want + * to, you can run this method on the members of a group, or on any other + * filtered list of people and get a header relevant to them (e.g., if + * they only have home addresses, the work address fields won't show up). + */ +MacabHeader *MacabRecords::createHeaderForRecordType(const CFArrayRef _records, const CFStringRef _recordType) const +{ + /* We have two types of properties for a given record type, nonrequired + * and required. Required properties are ones that will show up whether + * or not they are empty. Nonrequired properties will only show up if + * at least one record in the set has that property filled. The reason + * is that some properties, like the kABTitleProperty are required by + * the mail merge wizard (in module sw) but are by default not shown in + * the macOS address book, so they would be weeded out at this stage + * and not shown if they were not required. + * + * Note: with the addition of required properties, I am not sure that + * this method still works for kABGroupRecordType (since the required + * properties are all for kABPersonRecordType). + * + * Note: required properties are constructed in the method + * bootstrap_requiredProperties() (above). + */ + CFArrayRef allProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType); + CFStringRef *nonRequiredProperties; + sal_Int32 numRecords = static_cast<sal_Int32>(CFArrayGetCount(_records)); + sal_Int32 numProperties = static_cast<sal_Int32>(CFArrayGetCount(allProperties)); + sal_Int32 numNonRequiredProperties = numProperties - requiredProperties.size(); + + /* While searching through the properties for required properties, these + * sal_Bools will keep track of what we have found. + */ + bool bFoundRequiredProperties[requiredProperties.size()]; + + + /* We have three MacabHeaders: headerDataForProperty is where we + * store the result of createHeaderForProperty(), which return a + * MacabHeader for a single property. lcl_header is where we store + * the MacabHeader that we are constructing. And, nonRequiredHeader + * is where we construct the MacabHeader for non-required properties, + * so that we can sort them before adding them to lcl_header. + */ + MacabHeader *headerDataForProperty; + MacabHeader *lcl_header = new MacabHeader(); + MacabHeader *nonRequiredHeader = new MacabHeader(); + + /* Other variables... */ + sal_Int32 k; + ABRecordRef record; + CFStringRef property; + + + /* Allocate and initialize... */ + nonRequiredProperties = new CFStringRef[numNonRequiredProperties]; + k = 0; + for(std::vector<CFStringRef>::size_type i = 0; i < requiredProperties.size(); i++) + bFoundRequiredProperties[i] = false; + + /* Determine the non-required properties... */ + for(sal_Int32 i = 0; i < numProperties; i++) + { + bool bFoundProperty = false; + property = static_cast<CFStringRef>(CFArrayGetValueAtIndex(allProperties, i)); + for(std::vector<CFStringRef>::size_type j = 0; j < requiredProperties.size(); j++) + { + if(CFEqual(property, requiredProperties[j])) + { + bFoundProperty = true; + bFoundRequiredProperties[j] = true; + break; + } + } + + if(!bFoundProperty) + { + /* If we have found too many non-required properties */ + if(k == numNonRequiredProperties) + { + k++; // so that the OSL_ENSURE below fails + break; + } + nonRequiredProperties[k] = property; + k++; + } + } + + // Somehow, we got too many or too few non-required properties... + // Most likely, one of the required properties no longer exists, which + // we also test later. + OSL_ENSURE(k == numNonRequiredProperties, "MacabRecords::createHeaderForRecordType: Found an unexpected number of non-required properties"); + + /* Fill the header with required properties first... */ + for(std::vector<CFStringRef>::size_type i = 0; i < requiredProperties.size(); i++) + { + if(bFoundRequiredProperties[i]) + { + /* The order of these matters (we want all address properties + * before any phone properties, or else things will look weird), + * so we get all possibilities for each property, going through + * each record, and then go onto the next property. + * (Note: the reason that we have to go through all records + * in the first place is that properties like address, phone, and + * e-mail are multi-value properties with an unknown number of + * values. A user could specify thirteen different kinds of + * e-mail addresses for one of her or his contacts, and we need to + * get all of them. + */ + for(sal_Int32 j = 0; j < numRecords; j++) + { + record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(_records, j)); + headerDataForProperty = createHeaderForProperty(record,requiredProperties[i],_recordType,true); + if(headerDataForProperty != nullptr) + { + (*lcl_header) += headerDataForProperty; + delete headerDataForProperty; + } + } + } + else + { + // Couldn't find a required property... + OSL_FAIL(OString("MacabRecords::createHeaderForRecordType: could not find required property: " + + OUStringToOString(CFStringToOUString(requiredProperties[i]), RTL_TEXTENCODING_ASCII_US)).getStr()); + } + } + + /* And now, non-required properties... */ + for(sal_Int32 i = 0; i < numRecords; i++) + { + record = const_cast<ABRecordRef>(CFArrayGetValueAtIndex(_records, i)); + + for(sal_Int32 j = 0; j < numNonRequiredProperties; j++) + { + property = nonRequiredProperties[j]; + headerDataForProperty = createHeaderForProperty(record,property,_recordType,false); + if(headerDataForProperty != nullptr) + { + (*nonRequiredHeader) += headerDataForProperty; + delete headerDataForProperty; + } + } + + } + nonRequiredHeader->sortRecord(); + + (*lcl_header) += nonRequiredHeader; + delete nonRequiredHeader; + + CFRelease(allProperties); + delete [] nonRequiredProperties; + + return lcl_header; +} + + +/* Create a header for a single property. Basically, this method gets + * the property's value and type and then calls another method of + * the same name to do the dirty work. + */ +MacabHeader *MacabRecords::createHeaderForProperty(const ABRecordRef _record, const CFStringRef _propertyName, const CFStringRef _recordType, const bool _isPropertyRequired) const +{ + // local variables + CFStringRef localizedPropertyName; + CFTypeRef propertyValue; + ABPropertyType propertyType; + MacabHeader *result; + + /* Get the property's value */ + propertyValue = ABRecordCopyValue(_record,_propertyName); + if(propertyValue == nullptr && !_isPropertyRequired) + return nullptr; + + propertyType = ABTypeOfProperty(addressBook, _recordType, _propertyName); + localizedPropertyName = ABCopyLocalizedPropertyOrLabel(_propertyName); + + result = createHeaderForProperty(propertyType, propertyValue, localizedPropertyName); + + if(propertyValue != nullptr) + CFRelease(propertyValue); + + return result; +} + + +/* Create a header for a single property. This method is recursive + * because a single property might contain several sub-properties that + * we also want to treat singly. + */ +MacabHeader *MacabRecords::createHeaderForProperty(const ABPropertyType _propertyType, const CFTypeRef _propertyValue, const CFStringRef _propertyName) const +{ + macabfield **headerNames = nullptr; + sal_Int32 length = 0; + + switch(_propertyType) + { + /* Scalars */ + case kABStringProperty: + case kABRealProperty: + case kABIntegerProperty: + case kABDateProperty: + length = 1; + headerNames = new macabfield *[1]; + headerNames[0] = new macabfield; + headerNames[0]->value = _propertyName; + headerNames[0]->type = _propertyType; + break; + + /* Multi-scalars */ + case kABMultiIntegerProperty: + case kABMultiDateProperty: + case kABMultiStringProperty: + case kABMultiRealProperty: + case kABMultiDataProperty: + /* For non-scalars, we can only get more information if the property + * actually exists. + */ + if(_propertyValue != nullptr) + { + sal_Int32 i; + + sal_Int32 multiLength = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))); + CFStringRef multiLabel, localizedMultiLabel; + OUString multiLabelString; + OUString multiPropertyString; + OUString headerNameString; + ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100); + + length = multiLength; + headerNames = new macabfield *[multiLength]; + multiPropertyString = CFStringToOUString(_propertyName); + + /* Go through each element, and - since each element is a scalar - + * just create a new macabfield for it. + */ + for(i = 0; i < multiLength; i++) + { + multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i); + localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel); + multiLabelString = CFStringToOUString(localizedMultiLabel); + CFRelease(multiLabel); + CFRelease(localizedMultiLabel); + headerNameString = multiPropertyString + ": " + fixLabel(multiLabelString); + headerNames[i] = new macabfield; + headerNames[i]->value = OUStringToCFString(headerNameString); + headerNames[i]->type = multiType; + } + } + break; + + /* Multi-array or dictionary */ + case kABMultiArrayProperty: + case kABMultiDictionaryProperty: + /* For non-scalars, we can only get more information if the property + * actually exists. + */ + if(_propertyValue != nullptr) + { + sal_Int32 i,j,k; + + // Total number of multi-array or multi-dictionary elements. + sal_Int32 multiLengthFirstLevel = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))); + + /* Total length, including the length of each element (e.g., if + * this multi-dictionary contains three dictionaries, and each + * dictionary has four elements, this variable will be twelve, + * whereas multiLengthFirstLevel will be three. + */ + sal_Int32 multiLengthSecondLevel = 0; + + CFStringRef multiLabel, localizedMultiLabel; + CFTypeRef multiValue; + OUString multiLabelString; + OUString multiPropertyString; + std::vector<std::unique_ptr<MacabHeader>> multiHeaders; + ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100); + + multiPropertyString = CFStringToOUString(_propertyName); + + /* Go through each element - since each element can really + * contain anything, we run this method again on each element + * and store the resulting MacabHeader (in the multiHeaders + * array). Then, all we'll have to do is combine the MacabHeaders + * into a single one. + */ + for(i = 0; i < multiLengthFirstLevel; i++) + { + /* label */ + multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i); + multiValue = ABMultiValueCopyValueAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i); + std::unique_ptr<MacabHeader> hdr; + if(multiValue && multiLabel) + { + localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel); + multiLabelString = multiPropertyString + ": " + fixLabel(CFStringToOUString(localizedMultiLabel)); + CFRelease(multiLabel); + CFRelease(localizedMultiLabel); + multiLabel = OUStringToCFString(multiLabelString); + hdr.reset(createHeaderForProperty(multiType, multiValue, multiLabel)); + if (!hdr) + hdr = std::make_unique<MacabHeader>(); + multiLengthSecondLevel += hdr->getSize(); + } + else + { + hdr = std::make_unique<MacabHeader>(); + } + if(multiValue) + CFRelease(multiValue); + if(multiLabel) + CFRelease(multiLabel); + multiHeaders.push_back(std::move(hdr)); + } + + /* We now have enough information to create our final MacabHeader. + * We go through each field of each header and add it to the + * headerNames array (which is what is used below to construct + * the MacabHeader we return). + */ + length = multiLengthSecondLevel; + headerNames = new macabfield *[multiLengthSecondLevel]; + + for(i = 0, j = 0, k = 0; i < multiLengthSecondLevel; i++,k++) + { + while(multiHeaders[j]->getSize() == k) + { + j++; + k = 0; + } + + headerNames[i] = multiHeaders[j]->copy(k); + } + } + break; + + /* Dictionary */ + case kABDictionaryProperty: + /* For non-scalars, we can only get more information if the property + * actually exists. + */ + if(_propertyValue != nullptr) + { + /* Assume all keys are strings */ + sal_Int32 numRecords = static_cast<sal_Int32>(CFDictionaryGetCount(static_cast<CFDictionaryRef>(_propertyValue))); + + /* The only method for getting info out of a CFDictionary, of both + * keys and values, is to all of them all at once, so these + * variables will hold them. + */ + CFStringRef *dictKeys; + CFTypeRef *dictValues; + + sal_Int32 i,j,k; + OUString dictKeyString, propertyNameString; + ABPropertyType dictType; + MacabHeader **dictHeaders = new MacabHeader *[numRecords]; + OUString dictLabelString; + CFStringRef dictLabel, localizedDictKey; + + /* Get the keys and values */ + dictKeys = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)*numRecords)); + dictValues = static_cast<CFTypeRef *>(malloc(sizeof(CFTypeRef)*numRecords)); + CFDictionaryGetKeysAndValues(static_cast<CFDictionaryRef>(_propertyValue), reinterpret_cast<const void **>(dictKeys), dictValues); + + propertyNameString = CFStringToOUString(_propertyName); + + length = 0; + /* Go through each element - assuming that the key is a string but + * that the value could be anything. Since the value could be + * anything, we can't assume that it is scalar (it could even be + * another dictionary), so we attempt to get its type using + * the method getABTypeFromCFType and then run this method + * recursively on that element, storing the MacabHeader that + * results. Then, we just combine all of the MacabHeaders into + * one. + */ + for(i = 0; i < numRecords; i++) + { + dictType = getABTypeFromCFType( CFGetTypeID(dictValues[i]) ); + localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]); + dictKeyString = CFStringToOUString(localizedDictKey); + dictLabelString = propertyNameString + ": " + fixLabel(dictKeyString); + dictLabel = OUStringToCFString(dictLabelString); + dictHeaders[i] = createHeaderForProperty(dictType, dictValues[i], dictLabel); + if (!dictHeaders[i]) + dictHeaders[i] = new MacabHeader(); + length += dictHeaders[i]->getSize(); + CFRelease(dictLabel); + CFRelease(localizedDictKey); + } + + /* Combine all of the macabfields in each MacabHeader into the + * headerNames array, which (at the end of this method) is used + * to create the MacabHeader that is returned. + */ + headerNames = new macabfield *[length]; + for(i = 0, j = 0, k = 0; i < length; i++,k++) + { + while(dictHeaders[j]->getSize() == k) + { + j++; + k = 0; + } + + headerNames[i] = dictHeaders[j]->copy(k); + } + + for(i = 0; i < numRecords; i++) + delete dictHeaders[i]; + + delete [] dictHeaders; + free(dictKeys); + free(dictValues); + } + break; + + /* Array */ + case kABArrayProperty: + /* For non-scalars, we can only get more information if the property + * actually exists. + */ + if(_propertyValue != nullptr) + { + sal_Int32 arrLength = static_cast<sal_Int32>(CFArrayGetCount(static_cast<CFArrayRef>(_propertyValue))); + sal_Int32 i,j,k; + CFTypeRef arrValue; + ABPropertyType arrType; + std::vector<std::unique_ptr<MacabHeader>> arrHeaders; + OUString propertyNameString = CFStringToOUString(_propertyName); + OUString arrLabelString; + CFStringRef arrLabel; + + length = 0; + /* Go through each element - since the elements here do not have + * unique keys like the ones in dictionaries, we create a unique + * key out of the id of the element in the array (the first + * element gets a 0 plopped onto the end of it, the second a 1... + * As with dictionaries, the elements could be anything, including + * another array, so we have to run this method recursively on + * each element, storing the resulting MacabHeader into an array, + * which we then combine into one MacabHeader that is returned. + */ + for(i = 0; i < arrLength; i++) + { + arrValue = CFArrayGetValueAtIndex(static_cast<CFArrayRef>(_propertyValue), i); + arrType = getABTypeFromCFType( CFGetTypeID(arrValue) ); + arrLabelString = propertyNameString + OUString::number(i); + arrLabel = OUStringToCFString(arrLabelString); + auto hdr = std::unique_ptr<MacabHeader>(createHeaderForProperty(arrType, arrValue, arrLabel)); + if (!hdr) + hdr = std::make_unique<MacabHeader>(); + length += hdr->getSize(); + CFRelease(arrLabel); + arrHeaders.push_back(std::move(hdr)); + } + + headerNames = new macabfield *[length]; + for(i = 0, j = 0, k = 0; i < length; i++,k++) + { + while(arrHeaders[j]->getSize() == k) + { + j++; + k = 0; + } + + headerNames[i] = arrHeaders[j]->copy(k); + } + } + break; + + default: + break; + + } + + /* If we succeeded at adding elements to the headerNames array, then + * length will no longer be 0. If it is, create a new MacabHeader + * out of the headerNames (after weeding out duplicate headers), and + * then return the result. If the length is still 0, return NULL: we + * failed to create a MacabHeader out of this property. + */ + if(length != 0) + { + manageDuplicateHeaders(headerNames, length); + MacabHeader *headerResult = new MacabHeader(length, headerNames); + for(sal_Int32 i = 0; i < length; ++i) + delete headerNames[i]; + delete [] headerNames; + return headerResult; + } + else + return nullptr; +} + + +/* Create a MacabRecord out of an ABRecord, using a given MacabHeader and + * the record's type. We go through each property for this record type + * then process it much like we processed the header (above), with two + * exceptions: if we come upon something not in the header, we ignore it + * (it's something we don't want to add), and once we find a corresponding + * location in the header, we store the property and the property type in + * a macabfield. (For the header, we stored the property type and the name + * of the property as a CFString.) + */ +MacabRecord *MacabRecords::createMacabRecord(const ABRecordRef _abrecord, const MacabHeader *_header, const CFStringRef _recordType) const +{ + /* The new record that we will create... */ + MacabRecord *macabRecord = new MacabRecord(_header->getSize()); + + CFArrayRef recordProperties = ABCopyArrayOfPropertiesForRecordType(addressBook, _recordType); + sal_Int32 numProperties = static_cast<sal_Int32>(CFArrayGetCount(recordProperties)); + + sal_Int32 i; + + CFTypeRef propertyValue; + ABPropertyType propertyType; + + CFStringRef propertyName, localizedPropertyName; + OUString propertyNameString; + for(i = 0; i < numProperties; i++) + { + propertyName = static_cast<CFStringRef>(CFArrayGetValueAtIndex(recordProperties, i)); + localizedPropertyName = ABCopyLocalizedPropertyOrLabel(propertyName); + propertyNameString = CFStringToOUString(localizedPropertyName); + CFRelease(localizedPropertyName); + + /* Get the property's value */ + propertyValue = ABRecordCopyValue(_abrecord,propertyName); + if(propertyValue != nullptr) + { + propertyType = ABTypeOfProperty(addressBook, _recordType, propertyName); + if(propertyType != kABErrorInProperty) + insertPropertyIntoMacabRecord(propertyType, macabRecord, _header, propertyNameString, propertyValue); + + CFRelease(propertyValue); + } + } + CFRelease(recordProperties); + return macabRecord; +} + + +/* Inserts a given property into a MacabRecord. This method calls another + * method by the same name after getting the property type (it only + * receives the property value). It is called when we aren't given the + * property's type already. + */ +void MacabRecords::insertPropertyIntoMacabRecord(MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const +{ + CFTypeID cf_type = CFGetTypeID(_propertyValue); + ABPropertyType ab_type = getABTypeFromCFType( cf_type ); + + if(ab_type != kABErrorInProperty) + insertPropertyIntoMacabRecord(ab_type, _abrecord, _header, _propertyName, _propertyValue); +} + + +/* Inserts a given property into a MacabRecord. This method is recursive + * because properties can contain many sub-properties. + */ +void MacabRecords::insertPropertyIntoMacabRecord(const ABPropertyType _propertyType, MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const +{ + /* If there is no value, return */ + if(_propertyValue == nullptr) + return; + + /* The main switch statement */ + switch(_propertyType) + { + /* Scalars */ + case kABStringProperty: + case kABRealProperty: + case kABIntegerProperty: + case kABDateProperty: + { + /* Only scalars actually insert a property into the MacabRecord. + * In all other cases, this method is called recursively until a + * scalar type, an error, or an unknown type are found. + * Because of that, the following checks only occur for this type. + * We store whether we have successfully placed this property + * into the MacabRecord (or whether an unrecoverable error occurred). + * Then, we try over and over again to place the property into the + * record. There are three possible results: + * 1) Success! + * 2) There is already a property stored at the column of this name, + * in which case we have a duplicate header (see the method + * manageDuplicateHeaders()). If that is the case, we add an ID + * to the end of the column name in the same format as we do in + * manageDuplicateHeaders() and try again. + * 3) No column of this name exists in the header. In this case, + * there is nothing we can do: we have failed to place this + * property into the record. + */ + bool bPlaced = false; + OUString columnName = _propertyName; + sal_Int32 i = 1; + + // A big safeguard to prevent two fields from having the same name. + while(!bPlaced) + { + sal_Int32 columnNumber = _header->getColumnNumber(columnName); + bPlaced = true; + if(columnNumber != -1) + { + // collision! A property already exists here! + if(_abrecord->get(columnNumber) != nullptr) + { + bPlaced = false; + i++; + columnName = _propertyName + " (" + OUString::number(i) + ")"; + } + + // success! + else + { + _abrecord->insertAtColumn(_propertyValue, _propertyType, columnNumber); + } + } + } + } + break; + + /* Array */ + case kABArrayProperty: + { + /* An array is basically just a list of anything, so all we do + * is go through the array, and rerun this method recursively + * on each element. + */ + sal_Int32 arrLength = static_cast<sal_Int32>(CFArrayGetCount(static_cast<CFArrayRef>(_propertyValue))); + sal_Int32 i; + OUString newPropertyName; + + /* Going through each element... */ + for(i = 0; i < arrLength; i++) + { + const void *arrValue = CFArrayGetValueAtIndex(static_cast<CFArrayRef>(_propertyValue), i); + newPropertyName = _propertyName + OUString::number(i); + insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, arrValue); + CFRelease(arrValue); + } + + } + break; + + /* Dictionary */ + case kABDictionaryProperty: + { + /* A dictionary is basically a hashmap. Technically, it can + * hold any object as a key and any object as a value. + * For our case, we assume that the key is a string (so that + * we can use the key to get the column name and match it against + * the header), but we don't assume anything about the value, so + * we run this method recursively (or, rather, we run the version + * of this method for when we don't know the object's type) until + * we hit a scalar value. + */ + + sal_Int32 numRecords = static_cast<sal_Int32>(CFDictionaryGetCount(static_cast<CFDictionaryRef>(_propertyValue))); + OUString dictKeyString; + sal_Int32 i; + OUString newPropertyName; + + /* Unfortunately, the only way to get both keys and values out + * of a dictionary in Carbon is to get them all at once, so we + * do that. + */ + CFStringRef *dictKeys; + CFStringRef localizedDictKey; + CFTypeRef *dictValues; + dictKeys = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)*numRecords)); + dictValues = static_cast<CFTypeRef *>(malloc(sizeof(CFTypeRef)*numRecords)); + CFDictionaryGetKeysAndValues(static_cast<CFDictionaryRef>(_propertyValue), reinterpret_cast<const void **>(dictKeys), dictValues); + + /* Going through each element... */ + for(i = 0; i < numRecords; i++) + { + localizedDictKey = ABCopyLocalizedPropertyOrLabel(dictKeys[i]); + dictKeyString = CFStringToOUString(localizedDictKey); + CFRelease(localizedDictKey); + newPropertyName = _propertyName + ": " + fixLabel(dictKeyString); + insertPropertyIntoMacabRecord(_abrecord, _header, newPropertyName, dictValues[i]); + } + + free(dictKeys); + free(dictValues); + } + break; + + /* Multivalue */ + case kABMultiIntegerProperty: + case kABMultiDateProperty: + case kABMultiStringProperty: + case kABMultiRealProperty: + case kABMultiDataProperty: + case kABMultiDictionaryProperty: + case kABMultiArrayProperty: + { + /* All scalar multivalues are handled in the same way. Each element + * is a label and a value. All labels are strings + * (kABStringProperty), and all values have the same type + * (which is the type of the multivalue minus 255, or as + * Carbon's list of property types has it, minus 0x100. + * We just get the correct type, then go through each element + * and get the label and value and print them in a list. + */ + + sal_Int32 i; + sal_Int32 multiLength = ABMultiValueCount(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))); + CFStringRef multiLabel, localizedMultiLabel; + CFTypeRef multiValue; + OUString multiLabelString, newPropertyName; + ABPropertyType multiType = static_cast<ABPropertyType>(ABMultiValuePropertyType(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue))) - 0x100); + + /* Go through each element... */ + for(i = 0; i < multiLength; i++) + { + /* Label and value */ + multiLabel = ABMultiValueCopyLabelAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i); + multiValue = ABMultiValueCopyValueAtIndex(static_cast<ABMutableMultiValueRef>(const_cast<void *>(_propertyValue)), i); + + localizedMultiLabel = ABCopyLocalizedPropertyOrLabel(multiLabel); + multiLabelString = CFStringToOUString(localizedMultiLabel); + newPropertyName = _propertyName + ": " + fixLabel(multiLabelString); + insertPropertyIntoMacabRecord(multiType, _abrecord, _header, newPropertyName, multiValue); + + /* free our variables */ + CFRelease(multiLabel); + CFRelease(localizedMultiLabel); + CFRelease(multiValue); + } + } + break; + + /* Unhandled types */ + case kABErrorInProperty: + case kABDataProperty: + default: + /* An error, as far as I have seen, only shows up as a type + * returned by a function for dictionaries when the dictionary + * holds many types of values. Since we do not use that function, + * it shouldn't come up. I have yet to see the kABDataProperty, + * and I am not sure how to represent it as a string anyway, + * since it appears to just be a bunch of bytes. Assumably, if + * these bytes made up a string, the type would be + * kABStringProperty. I think that this is used when we are not + * sure what the type is (e.g., it could be a string or a number). + * That being the case, I still don't know how to represent it. + * And, default should never come up, since we've exhausted all + * of the possible types for ABPropertyType, but... just in case. + */ + break; + } + +} + + +ABPropertyType MacabRecords::getABTypeFromCFType(const CFTypeID cf_type ) const +{ + for(auto const & i: lcl_CFTypes) + { + /* A match! */ + if(i.cf == cf_type) + { + return static_cast<ABPropertyType>(i.ab); + } + } + return kABErrorInProperty; +} + + +sal_Int32 MacabRecords::size() const +{ + return currentRecord; +} + + +MacabRecords *MacabRecords::begin() +{ + return this; +} + + +MacabRecords::iterator::iterator () +{ +} + + +MacabRecords::iterator::~iterator () +{ +} + + +MacabRecords::iterator& MacabRecords::iterator::operator= (MacabRecords *_records) +{ + id = 0; + records = _records; + return *this; +} + + +void MacabRecords::iterator::operator++ () +{ + id++; +} + + +bool MacabRecords::iterator::operator!= (const sal_Int32 i) const +{ + return(id != i); +} + + +bool MacabRecords::iterator::operator== (const sal_Int32 i) const +{ + return(id == i); +} + + +MacabRecord *MacabRecords::iterator::operator* () const +{ + return records->getRecord(id); +} + + +sal_Int32 MacabRecords::end() const +{ + return currentRecord; +} + + +void MacabRecords::swap(const sal_Int32 _id1, const sal_Int32 _id2) +{ + MacabRecord *swapRecord = records[_id1]; + + records[_id1] = records[_id2]; + records[_id2] = swapRecord; +} + + +void MacabRecords::setName(const OUString& _sName) +{ + m_sName = _sName; +} + + +OUString const & MacabRecords::getName() const +{ + return m_sName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabRecords.hxx b/connectivity/source/drivers/macab/MacabRecords.hxx new file mode 100644 index 000000000..1e7d9975d --- /dev/null +++ b/connectivity/source/drivers/macab/MacabRecords.hxx @@ -0,0 +1,131 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRECORDS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRECORDS_HXX + +#include <sal/config.h> + +#include <vector> + +#include "MacabRecord.hxx" +#include "MacabHeader.hxx" + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> +#include <com/sun/star/util/DateTime.hpp> + +namespace connectivity +{ + namespace macab + { + /* This struct is for converting CF types to AB types (Core Foundation + * types to Address Book types). + */ + struct lcl_CFType { + CFTypeID cf; + sal_Int32 ab; + }; + + class MacabRecords{ + protected: + /* MacabRecords is, at its core, a table of macabfields, in the + * form of a header and a list of objects of type MacabRecord. + * It also has a unique name that refers to the name of the table. + */ + sal_Int32 recordsSize; + sal_Int32 currentRecord; + CFStringRef recordType; + MacabHeader *header; + MacabRecord **records; + ABAddressBookRef addressBook; + OUString m_sName; + + /* For converting CF types to AB types */ + std::vector<lcl_CFType> lcl_CFTypes; + + /* For required properties */ + std::vector<CFStringRef> requiredProperties; + + private: + /* All of the private methods are for creating a MacabHeader or a + * MacabRecord. They are used by the initialize method that goes + * about filling a MacabRecords using all of the records in the + * macOS Address Book. + */ + void bootstrap_CF_types(); + void bootstrap_requiredProperties(); + MacabHeader *createHeaderForProperty(const ABRecordRef _record, const CFStringRef _propertyName, const CFStringRef _recordType, const bool _isPropertyRequired) const; + MacabHeader *createHeaderForProperty(const ABPropertyType _propertyType, const CFTypeRef _propertyValue, const CFStringRef _propertyName) const; + ABPropertyType getABTypeFromCFType(const CFTypeID cf_type ) const; + void insertPropertyIntoMacabRecord(MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const; + void insertPropertyIntoMacabRecord(const ABPropertyType _propertyType, MacabRecord *_abrecord, const MacabHeader *_header, const OUString& _propertyName, const CFTypeRef _propertyValue) const; + public: + MacabRecords(const ABAddressBookRef _addressBook, MacabHeader *_header, MacabRecord **_records, sal_Int32 _numRecords); + explicit MacabRecords(const MacabRecords *_copy); + explicit MacabRecords(const ABAddressBookRef _addressBook); + ~MacabRecords(); + + void initialize(); + + void setHeader(MacabHeader *_header); + MacabHeader *getHeader() const; + + void setName(const OUString& _sName); + OUString const & getName() const; + + MacabRecord *insertRecord(MacabRecord *_newRecord, const sal_Int32 _location); + void insertRecord(MacabRecord *_newRecord); + MacabRecord *getRecord(const sal_Int32 _location) const; + void swap(const sal_Int32 _id1, const sal_Int32 _id2); + + macabfield *getField(const sal_Int32 _recordNumber, const sal_Int32 _columnNumber) const; + macabfield *getField(const sal_Int32 _recordNumber, const OUString& _columnName) const; + sal_Int32 getFieldNumber(const OUString& _columnName) const; + + sal_Int32 size() const; + + MacabHeader *createHeaderForRecordType(const CFArrayRef _records, const CFStringRef _recordType) const; + MacabRecord *createMacabRecord(const ABRecordRef _abrecord, const MacabHeader *_header, const CFStringRef _recordType) const; + + MacabRecords *begin(); + sal_Int32 end() const; + class iterator{ + protected: + MacabRecords *records; + public: + sal_Int32 id; + iterator& operator= (MacabRecords *_records); + iterator(); + ~iterator(); + void operator++ (); + bool operator!= (const sal_Int32 i) const; + bool operator== (const sal_Int32 i) const; + MacabRecord *operator* () const; + }; + + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRECORDS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabResultSet.cxx b/connectivity/source/drivers/macab/MacabResultSet.cxx new file mode 100644 index 000000000..7b0911223 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabResultSet.cxx @@ -0,0 +1,1074 @@ +/* -*- 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 "MacabResultSet.hxx" +#include "MacabAddressBook.hxx" +#include "MacabRecords.hxx" +#include "macabutilities.hxx" +#include "MacabResultSetMetaData.hxx" +#include "MacabConnection.hxx" +#include "macabcondition.hxx" +#include "macaborder.hxx" +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <TConnection.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> +#include <resource/sharedresources.hxx> +#include <strings.hrc> + +using namespace connectivity::macab; +using namespace cppu; +using namespace css::uno; +using namespace css::lang; +using namespace css::beans; +using namespace css::sdbc; +using namespace css::sdbcx; +using namespace css::io; +using namespace css::util; + +IMPLEMENT_SERVICE_INFO(MacabResultSet, "com.sun.star.sdbc.drivers.MacabResultSet", "com.sun.star.sdbc.ResultSet"); + +MacabResultSet::MacabResultSet(MacabCommonStatement* pStmt) + : MacabResultSet_BASE(m_aMutex), + OPropertySetHelper(MacabResultSet_BASE::rBHelper), + m_xStatement(pStmt), + m_aMacabRecords(), + m_nRowPos(-1), + m_bWasNull(true), + m_sTableName(MacabAddressBook::getDefaultTableName()) +{ +} + +MacabResultSet::~MacabResultSet() +{ +} + +void MacabResultSet::allMacabRecords() +{ + MacabConnection* pConnection = static_cast< MacabConnection *>(m_xStatement->getConnection().get()); + + m_aMacabRecords = pConnection->getAddressBook()->getMacabRecords(m_sTableName); +} + +void MacabResultSet::someMacabRecords(const MacabCondition *pCondition) +{ + MacabConnection* pConnection = static_cast< MacabConnection *>(m_xStatement->getConnection().get()); + MacabRecords* allRecords; + + allRecords = pConnection->getAddressBook()->getMacabRecords(m_sTableName); + + // Bad table!! Throw exception? + if(allRecords == nullptr) + return; + + if(m_aMacabRecords != nullptr && m_aMacabRecords != allRecords) + delete m_aMacabRecords; + + // The copy constructor copies everything but records (including the + // maximum allocated size, which means that we'll never have to resize) + m_aMacabRecords = new MacabRecords(allRecords); + + if(pCondition->isAlwaysFalse()) + { + return; + } + + MacabRecords::iterator iterator; + + for (iterator = allRecords->begin(); + iterator != allRecords->end(); + ++iterator) + { + if (pCondition->eval(*iterator)) + m_aMacabRecords->insertRecord(*iterator); + } +} + +void MacabResultSet::sortMacabRecords(const MacabOrder *pOrder) +{ + // I do this with ints rather than an iterator because the ids will + // be changing when we change the order and ints are easier to deal + // with (for me). + sal_Int32 i, j, size, smallest; + size = m_aMacabRecords->size(); + + for(i = 0; i < size; i++) + { + smallest = i; + for( j = i + 1; j < size; j++) + { + // if smallest > j + if(pOrder->compare(m_aMacabRecords->getRecord(smallest), + m_aMacabRecords->getRecord(j) ) > 0) + { + smallest = j; + } + + } + + if(smallest != i) + { + m_aMacabRecords->swap(i,smallest); + } + } + +} + +void MacabResultSet::setTableName(OUString const & _sTableName) +{ + m_sTableName = _sTableName; +} + +void MacabResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + + m_xStatement.clear(); + m_xMetaData.clear(); +} + +Any SAL_CALL MacabResultSet::queryInterface(const Type & rType) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + if (!aRet.hasValue()) + aRet = MacabResultSet_BASE::queryInterface(rType); + return aRet; +} + +void SAL_CALL MacabResultSet::acquire() throw() +{ + MacabResultSet_BASE::acquire(); +} + +void SAL_CALL MacabResultSet::release() throw() +{ + MacabResultSet_BASE::release(); +} + +Sequence< Type > SAL_CALL MacabResultSet::getTypes() +{ + 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(), MacabResultSet_BASE::getTypes()); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL MacabResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +sal_Int32 SAL_CALL MacabResultSet::findColumn(const OUString& columnName) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + // find the first column with the name columnName + Reference< XResultSetMetaData > xMeta = getMetaData(); + sal_Int32 nLen = xMeta->getColumnCount(); + + for (sal_Int32 i = 1; i <= nLen; ++i) + { + if (xMeta->isCaseSensitive(i) ? + columnName == xMeta->getColumnName(i) : + columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i))) + return i; + } + + ::dbtools::throwInvalidColumnException( columnName, *this ); + assert(false); + return 0; // Never reached +} + +OUString SAL_CALL MacabResultSet::getString(sal_Int32 columnIndex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + OUString aRet; + sal_Int32 nRecords = m_aMacabRecords->size(); + m_bWasNull = true; + + if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is()) + { + sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex); + macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber); + if(aField != nullptr) + { + if(aField->type == kABStringProperty) + { + aRet = CFStringToOUString(static_cast<CFStringRef>(aField->value)); + m_bWasNull = false; + } + } + } + +// Trigger an exception if m_bWasNull is true? + return aRet; +} + +sal_Bool SAL_CALL MacabResultSet::getBoolean(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getBoolean", nullptr); + + return false; +} + +sal_Int8 SAL_CALL MacabResultSet::getByte(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getByte", nullptr); + + return 0; +} + +sal_Int16 SAL_CALL MacabResultSet::getShort(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getShort", nullptr); + + return 0; +} + +sal_Int32 SAL_CALL MacabResultSet::getInt(sal_Int32 columnIndex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nRet = 0; + sal_Int32 nRecords = m_aMacabRecords->size(); + m_bWasNull = true; + + if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is()) + { + sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex); + macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber); + if(aField != nullptr) + { + if(aField->type == kABIntegerProperty) + { + CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) ); + // m_bWasNull now becomes whether getting the value was successful + // Should we check for the wrong type here, e.g., a float or a 64 bit int? + m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nRet); + } + } + } + +// Trigger an exception if m_bWasNull is true? + return nRet; +} + +sal_Int64 SAL_CALL MacabResultSet::getLong(sal_Int32 columnIndex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int64 nRet = 0; + sal_Int32 nRecords = m_aMacabRecords->size(); + m_bWasNull = true; + + if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is()) + { + sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex); + macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber); + if(aField != nullptr) + { + if(aField->type == kABIntegerProperty) + { + CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) ); + // m_bWasNull now becomes whether getting the value was successful + // Should we check for the wrong type here, e.g., a float or a 32 bit int? + m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nRet); + } + } + } + +// Trigger an exception if m_bWasNull is true? + return nRet; +} + +float SAL_CALL MacabResultSet::getFloat(sal_Int32 columnIndex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + float nVal = 0; + sal_Int32 nRecords = m_aMacabRecords->size(); + m_bWasNull = true; + + if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is()) + { + sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex); + macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber); + if(aField != nullptr) + { + if(aField->type == kABRealProperty) + { + CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) ); + // m_bWasNull now becomes whether getting the value was successful + // Should we check for the wrong type here, e.g., an int or a double? + m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nVal); + } + } + } + +// Trigger an exception if m_bWasNull is true? + return nVal; +} + +double SAL_CALL MacabResultSet::getDouble(sal_Int32 columnIndex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + double nVal = 0; + sal_Int32 nRecords = m_aMacabRecords->size(); + m_bWasNull = true; + + if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is()) + { + sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex); + macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber); + if(aField != nullptr) + { + if(aField->type == kABRealProperty) + { + CFNumberType numberType = CFNumberGetType( static_cast<CFNumberRef>(aField->value) ); + // m_bWasNull now becomes whether getting the value was successful + // Should we check for the wrong type here, e.g., an int or a float? + m_bWasNull = !CFNumberGetValue(static_cast<CFNumberRef>(aField->value), numberType, &nVal); + } + } + } + +// Trigger an exception if m_bWasNull is true? + return nVal; +} + +Sequence< sal_Int8 > SAL_CALL MacabResultSet::getBytes(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getBytes", nullptr); + + return Sequence< sal_Int8 >(); +} + +Date SAL_CALL MacabResultSet::getDate(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getDate", nullptr); + + Date aRet; + return aRet; +} + +Time SAL_CALL MacabResultSet::getTime(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getTime", nullptr); + + css::util::Time nRet; + return nRet; +} + +DateTime SAL_CALL MacabResultSet::getTimestamp(sal_Int32 columnIndex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + DateTime nRet; + sal_Int32 nRecords = m_aMacabRecords->size(); + m_bWasNull = true; + + if (m_nRowPos != -1 && m_nRowPos != nRecords && m_xMetaData.is()) + { + sal_Int32 nFieldNumber = m_xMetaData->fieldAtColumn(columnIndex); + macabfield *aField = m_aMacabRecords->getField(m_nRowPos,nFieldNumber); + if(aField != nullptr) + { + if(aField->type == kABDateProperty) + { + nRet = CFDateToDateTime(static_cast<CFDateRef>(aField->value)); + m_bWasNull = false; + } + } + } + +// Trigger an exception if m_bWasNull is true? + return nRet; +} + +Reference< XInputStream > SAL_CALL MacabResultSet::getBinaryStream(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getBinaryStream", nullptr); + + return nullptr; +} + +Reference< XInputStream > SAL_CALL MacabResultSet::getCharacterStream(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getCharacterStream", nullptr); + + return nullptr; +} + +Any SAL_CALL MacabResultSet::getObject(sal_Int32, const Reference< css::container::XNameAccess >&) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getObject", nullptr); + + return Any(); +} + +Reference< XRef > SAL_CALL MacabResultSet::getRef(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getRef", nullptr); + + return nullptr; +} + +Reference< XBlob > SAL_CALL MacabResultSet::getBlob(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getBlob", nullptr); + + return nullptr; +} + +Reference< XClob > SAL_CALL MacabResultSet::getClob(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getClob", nullptr); + + return nullptr; +} + +Reference< XArray > SAL_CALL MacabResultSet::getArray(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException("getArray", nullptr); + + return nullptr; +} + +Reference< XResultSetMetaData > SAL_CALL MacabResultSet::getMetaData() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + if (!m_xMetaData.is()) + m_xMetaData = new MacabResultSetMetaData(m_xStatement->getOwnConnection(), m_sTableName); + + Reference< XResultSetMetaData > xMetaData = m_xMetaData.get(); + return xMetaData; +} + +sal_Bool SAL_CALL MacabResultSet::isBeforeFirst() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + if (m_nRowPos == -1) + return true; + + return false; +} + +sal_Bool SAL_CALL MacabResultSet::isAfterLast() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nRecords = m_aMacabRecords->size(); + if (m_nRowPos == nRecords) + return true; + + return false; +} + +sal_Bool SAL_CALL MacabResultSet::isFirst() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + if (m_nRowPos == 0) + return true; + + return false; +} + +sal_Bool SAL_CALL MacabResultSet::isLast() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nRecords = m_aMacabRecords->size(); + if (m_nRowPos == nRecords - 1) + return true; + + return false; +} + +void SAL_CALL MacabResultSet::beforeFirst() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + // move before the first row + m_nRowPos = -1; +} + +void SAL_CALL MacabResultSet::afterLast() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + // move after the last row + sal_Int32 nRecords = m_aMacabRecords->size(); + m_nRowPos = nRecords; +} + +void SAL_CALL MacabResultSet::close() +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + } + dispose(); +} + +sal_Bool SAL_CALL MacabResultSet::first() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nRecords = m_aMacabRecords->size(); + if (nRecords == 0) + return false; + + m_nRowPos = 0; + return true; +} + +sal_Bool SAL_CALL MacabResultSet::last() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nRecords = m_aMacabRecords->size(); + if (nRecords == 0) + return false; + + m_nRowPos = nRecords - 1; + return true; +} + +sal_Int32 SAL_CALL MacabResultSet::getRow() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return m_nRowPos; +} + +sal_Bool SAL_CALL MacabResultSet::absolute(sal_Int32 row) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nRecords = m_aMacabRecords->size(); + if (row <= -1 || + row >= nRecords) + return false; + + m_nRowPos = row; + return true; +} + +sal_Bool SAL_CALL MacabResultSet::relative(sal_Int32 row) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return absolute(m_nRowPos + row); +} + +sal_Bool SAL_CALL MacabResultSet::next() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return absolute(m_nRowPos + 1); +} + +sal_Bool SAL_CALL MacabResultSet::previous() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return absolute(m_nRowPos - 1); +} + +Reference< XInterface > SAL_CALL MacabResultSet::getStatement() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + Reference< XStatement > xStatement = m_xStatement.get(); + return xStatement; +} + +sal_Bool SAL_CALL MacabResultSet::rowDeleted() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL MacabResultSet::rowInserted() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL MacabResultSet::rowUpdated() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL MacabResultSet::wasNull() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + +void SAL_CALL MacabResultSet::cancel() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::clearWarnings() +{ +} + +Any SAL_CALL MacabResultSet::getWarnings() +{ + return Any(); +} + +void SAL_CALL MacabResultSet::insertRow() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + // you only have to implement this if you want to insert new rows +} + +void SAL_CALL MacabResultSet::updateRow() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + // only when you allow updates +} + +void SAL_CALL MacabResultSet::deleteRow() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::cancelRowUpdates() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::moveToInsertRow() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + // only when you allow inserts +} + +void SAL_CALL MacabResultSet::moveToCurrentRow() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateNull(sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateBoolean(sal_Int32, sal_Bool) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateByte(sal_Int32, sal_Int8) +{ + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); +} + +void SAL_CALL MacabResultSet::updateShort(sal_Int32, sal_Int16) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateInt(sal_Int32, sal_Int32) +{ + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); +} + +void SAL_CALL MacabResultSet::updateLong(sal_Int32, sal_Int64) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateFloat(sal_Int32, float) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateDouble(sal_Int32, double) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateString(sal_Int32, const OUString&) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateBytes(sal_Int32, const Sequence< sal_Int8 >&) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateDate(sal_Int32, const Date&) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateTime(sal_Int32, const css::util::Time&) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateTimestamp(sal_Int32, const DateTime&) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateBinaryStream(sal_Int32, const Reference< XInputStream >&, sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateCharacterStream(sal_Int32, const Reference< XInputStream >&, sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::refreshRow() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateObject(sal_Int32, const Any&) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL MacabResultSet::updateNumericObject(sal_Int32, const Any&, sal_Int32) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); +} + +// XRowLocate +Any SAL_CALL MacabResultSet::getBookmark() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nRecords = m_aMacabRecords->size(); + + if (m_nRowPos != -1 && m_nRowPos != nRecords) + { + macabfield *uidField = m_aMacabRecords->getField(m_nRowPos,OUString("UID")); + if(uidField != nullptr) + { + if(uidField->type == kABStringProperty) + { + return makeAny(CFStringToOUString( static_cast<CFStringRef>(uidField->value) )); + } + } + } + return Any(); +} + +sal_Bool SAL_CALL MacabResultSet::moveToBookmark(const Any& bookmark) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + OUString sBookmark = comphelper::getString(bookmark); + sal_Int32 nRecords = m_aMacabRecords->size(); + + for (sal_Int32 nRow = 0; nRow < nRecords; nRow++) + { + macabfield *uidField = m_aMacabRecords->getField(m_nRowPos,OUString("UID")); + if(uidField != nullptr) + { + if(uidField->type == kABStringProperty) + { + OUString sUniqueIdentifier = CFStringToOUString( static_cast<CFStringRef>(uidField->value) ); + if (sUniqueIdentifier == sBookmark) + { + m_nRowPos = nRow; + return true; + } + } + } + } + return false; +} + +sal_Bool SAL_CALL MacabResultSet::moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nRowSave = m_nRowPos; + + if (moveToBookmark(bookmark)) + { + sal_Int32 nRecords = m_aMacabRecords->size(); + + m_nRowPos += rows; + + if (-1 < m_nRowPos && m_nRowPos < nRecords) + return true; + } + + m_nRowPos = nRowSave; + return false; +} + +sal_Int32 SAL_CALL MacabResultSet::compareBookmarks(const Any& firstItem, const Any& secondItem) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + OUString sFirst = comphelper::getString(firstItem); + OUString sSecond = comphelper::getString(secondItem); + + if (sFirst < sSecond) + return CompareBookmark::LESS; + if (sFirst > sSecond) + return CompareBookmark::GREATER; + return CompareBookmark::EQUAL; +} + +sal_Bool SAL_CALL MacabResultSet::hasOrderedBookmarks() +{ + return false; +} + +sal_Int32 SAL_CALL MacabResultSet::hashBookmark(const Any& bookmark) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + OUString sBookmark = comphelper::getString(bookmark); + + return sBookmark.hashCode(); +} + +// XDeleteRows +Sequence< sal_Int32 > SAL_CALL MacabResultSet::deleteRows(const Sequence< Any >&) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(MacabResultSet_BASE::rBHelper.bDisposed); + + return Sequence< sal_Int32 >(); +} + +IPropertyArrayHelper* MacabResultSet::createArrayHelper() const +{ + Sequence< Property > aProps(6); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), + PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + return new OPropertyArrayHelper(aProps); +} + +IPropertyArrayHelper & MacabResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool MacabResultSet::convertFastPropertyValue( + Any &, + Any &, + sal_Int32 nHandle, + const Any& ) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + break; + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + default: + ; + } + return false; +} + +void MacabResultSet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const Any& ) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw Exception("cannot set prop " + OUString::number(nHandle), nullptr); + break; + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_FETCHSIZE: + break; + default: + ; + } +} + +void MacabResultSet::getFastPropertyValue( + Any& _rValue, + sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + _rValue <<= false; + break; + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + ; + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabResultSet.hxx b/connectivity/source/drivers/macab/MacabResultSet.hxx new file mode 100644 index 000000000..418a66c1f --- /dev/null +++ b/connectivity/source/drivers/macab/MacabResultSet.hxx @@ -0,0 +1,219 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRESULTSET_HXX + +#include "MacabStatement.hxx" +#include "MacabResultSetMetaData.hxx" +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> + +namespace connectivity +{ + namespace macab + { + /* + ** MacabResultSet + */ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, + css::sdbcx::XRowLocate, + css::sdbcx::XDeleteRows, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate, + css::lang::XServiceInfo> MacabResultSet_BASE; + class MacabRecords; + + class MacabResultSet : public cppu::BaseMutex, + public MacabResultSet_BASE, + public ::cppu::OPropertySetHelper, + public comphelper::OPropertyArrayUsageHelper<MacabResultSet> + { + protected: + ::rtl::Reference< MacabCommonStatement > m_xStatement; // the statement that has created this result set + ::rtl::Reference< MacabResultSetMetaData > m_xMetaData; // the description of the columns in this result set + MacabRecords * m_aMacabRecords; // address book entries matching the query + sal_Int32 m_nRowPos; // the current row within the result set + bool m_bWasNull; // last entry retrieved from this result set was NULL + OUString m_sTableName; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle) const override; + + // you can't delete objects of this type + virtual ~MacabResultSet() override; + + public: + DECLARE_SERVICE_INFO(); + + explicit MacabResultSet(MacabCommonStatement *pStmt); + + css::uno::Reference< css::uno::XInterface > operator *() + { + return css::uno::Reference< css::uno::XInterface >(*static_cast<MacabResultSet_BASE*>(this)); + } + + void allMacabRecords(); + void someMacabRecords(const class MacabCondition *pCondition); + void sortMacabRecords(const class MacabOrder *pOrder); + void setTableName(const OUString& _sTableName); + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // XResultSet + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + + // XCancellable + virtual void SAL_CALL cancel( ) override; + + // XCloseable + virtual void SAL_CALL close( ) override; + + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + + // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + + // XRowLocate + virtual css::uno::Any SAL_CALL getBookmark( ) override; + virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override; + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override; + virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& firstItem, const css::uno::Any& secondItem ) override; + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override; + virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override; + + // XDeleteRows + virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx b/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx new file mode 100644 index 000000000..38e7dca05 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx @@ -0,0 +1,215 @@ +/* -*- 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 "MacabResultSetMetaData.hxx" +#include "MacabHeader.hxx" +#include "MacabRecords.hxx" +#include "MacabAddressBook.hxx" +#include "macabutilities.hxx" +#include <strings.hrc> + +using namespace connectivity::macab; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; + +MacabResultSetMetaData::MacabResultSetMetaData(MacabConnection* _pConnection, OUString const & _sTableName) + : m_pConnection(_pConnection), + m_sTableName(_sTableName), + m_aMacabFields() +{ +} + +MacabResultSetMetaData::~MacabResultSetMetaData() +{ +} + +void MacabResultSetMetaData::setMacabFields(const ::rtl::Reference<connectivity::OSQLColumns> &xColumns) +{ + static const char aName[] = "Name"; + MacabRecords *aRecords; + MacabHeader *aHeader; + + aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName); + + // In case, somehow, we don't have anything with the name m_sTableName + if(aRecords == nullptr) + { + impl_throwError(STR_NO_TABLE); + } + + aHeader = aRecords->getHeader(); + + for (const auto& rxColumn : *xColumns) + { + OUString aFieldName; + sal_uInt32 nFieldNumber; + + rxColumn->getPropertyValue(aName) >>= aFieldName; + nFieldNumber = aHeader->getColumnNumber(aFieldName); + m_aMacabFields.push_back(nFieldNumber); + } + +} + +sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnDisplaySize(sal_Int32 /* column */) +{ + // For now, all columns are the same size. + return 50; +} + +sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnType(sal_Int32 column) +{ + MacabRecords *aRecords; + MacabHeader *aHeader; + macabfield *aField; + + aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName); + + // In case, somehow, we don't have anything with the name m_sTableName + if(aRecords == nullptr) + { + impl_throwError(STR_NO_TABLE); + } + + aHeader = aRecords->getHeader(); + aField = aHeader->get(column-1); + + if(aField == nullptr) + { + ::dbtools::throwInvalidIndexException(*this); + return -1; + } + + return ABTypeToDataType(aField->type); +} + +sal_Int32 SAL_CALL MacabResultSetMetaData::getColumnCount() +{ + return m_aMacabFields.size(); +} + +sal_Bool SAL_CALL MacabResultSetMetaData::isCaseSensitive(sal_Int32) +{ + return true; +} + +OUString SAL_CALL MacabResultSetMetaData::getSchemaName(sal_Int32) +{ + return OUString(); +} + +OUString SAL_CALL MacabResultSetMetaData::getColumnName(sal_Int32 column) +{ + sal_uInt32 nFieldNumber = m_aMacabFields[column - 1]; + MacabRecords *aRecords; + MacabHeader *aHeader; + + aRecords = m_pConnection->getAddressBook()->getMacabRecords(m_sTableName); + + // In case, somehow, we don't have anything with the name m_sTableName + if(aRecords == nullptr) + { + impl_throwError(STR_NO_TABLE); + } + + aHeader = aRecords->getHeader(); + OUString aName = aHeader->getString(nFieldNumber); + + return aName; +} + +OUString SAL_CALL MacabResultSetMetaData::getTableName(sal_Int32) +{ + return m_sTableName; +} + +OUString SAL_CALL MacabResultSetMetaData::getCatalogName(sal_Int32) +{ + return OUString(); +} + +OUString SAL_CALL MacabResultSetMetaData::getColumnTypeName(sal_Int32) +{ + return OUString(); +} + +OUString SAL_CALL MacabResultSetMetaData::getColumnLabel(sal_Int32) +{ + return OUString(); +} + +OUString SAL_CALL MacabResultSetMetaData::getColumnServiceName(sal_Int32) +{ + return OUString(); +} + +sal_Bool SAL_CALL MacabResultSetMetaData::isCurrency(sal_Int32) +{ + return false; +} + +sal_Bool SAL_CALL MacabResultSetMetaData::isAutoIncrement(sal_Int32) +{ + return false; +} + +sal_Bool SAL_CALL MacabResultSetMetaData::isSigned(sal_Int32) +{ + return false; +} + +sal_Int32 SAL_CALL MacabResultSetMetaData::getPrecision(sal_Int32) +{ + return 0; +} + +sal_Int32 SAL_CALL MacabResultSetMetaData::getScale(sal_Int32) +{ + return 0; +} + +sal_Int32 SAL_CALL MacabResultSetMetaData::isNullable(sal_Int32) +{ + return sal_Int32(true); +} + +sal_Bool SAL_CALL MacabResultSetMetaData::isSearchable(sal_Int32) +{ + return true; +} + +sal_Bool SAL_CALL MacabResultSetMetaData::isReadOnly(sal_Int32) +{ + return true; +} + +sal_Bool SAL_CALL MacabResultSetMetaData::isDefinitelyWritable(sal_Int32) +{ + return false; +} + +sal_Bool SAL_CALL MacabResultSetMetaData::isWritable(sal_Int32) +{ + return false; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx b/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx new file mode 100644 index 000000000..ec7c2c651 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx @@ -0,0 +1,87 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRESULTSETMETADATA_HXX + +#include "MacabConnection.hxx" +#include <connectivity/CommonTools.hxx> +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include <connectivity/dbexception.hxx> +#include <rtl/ref.hxx> + +namespace connectivity +{ + namespace macab + { + /* + ** MacabResultSetMetaData + */ + class MacabResultSetMetaData : public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> + { + MacabConnection* m_pConnection; + OUString m_sTableName; + std::vector<sal_Int32> m_aMacabFields; // for each selected column, contains the number + // of the corresponding AddressBook field + + protected: + virtual ~MacabResultSetMetaData() override; + + public: + MacabResultSetMetaData(MacabConnection* _pConnection, OUString const & _sTableName); + + // avoid ambiguous cast error from the compiler + operator css::uno::Reference< css::sdbc::XResultSetMetaData > () throw() + { return this; } + + /// @throws css::sdbc::SQLException + void setMacabFields( + const ::rtl::Reference<connectivity::OSQLColumns> &xColumns); + sal_uInt32 fieldAtColumn(sal_Int32 columnIndex) const + { return m_aMacabFields[columnIndex - 1]; } + + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABRESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabServices.cxx b/connectivity/source/drivers/macab/MacabServices.cxx new file mode 100644 index 000000000..a1cfc340c --- /dev/null +++ b/connectivity/source/drivers/macab/MacabServices.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 "MacabDriver.hxx" +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::macab; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* macab_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void*) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + MacabDriver::getImplementationName_Static(), + MacabDriver::getSupportedServiceNames_Static(), + &MacabDriver::Create, + ::cppu::createSingleFactory) + ; + + if (aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabStatement.cxx b/connectivity/source/drivers/macab/MacabStatement.cxx new file mode 100644 index 000000000..db6e3876b --- /dev/null +++ b/connectivity/source/drivers/macab/MacabStatement.cxx @@ -0,0 +1,594 @@ +/* -*- 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 "MacabStatement.hxx" +#include <sqlbison.hxx> +#include "MacabConnection.hxx" +#include "MacabAddressBook.hxx" +#include "MacabDriver.hxx" +#include "MacabResultSet.hxx" +#include "MacabResultSetMetaData.hxx" +#include "macabcondition.hxx" +#include "macaborder.hxx" +#include "macabutilities.hxx" +#include <TConnection.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <connectivity/dbexception.hxx> +#include <resource/sharedresources.hxx> +#include <strings.hrc> + +using namespace connectivity::macab; +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +namespace connectivity +{ + namespace macab + { + void impl_throwError(const char* pErrorId) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(pErrorId) ); + ::dbtools::throwGenericSQLException(sError,nullptr); + } + } +} + +IMPLEMENT_SERVICE_INFO(MacabStatement, "com.sun.star.sdbc.drivers.MacabStatement", "com.sun.star.sdbc.Statement"); + +MacabCommonStatement::MacabCommonStatement(MacabConnection* _pConnection ) + : MacabCommonStatement_BASE(m_aMutex), + OPropertySetHelper(rBHelper), + m_aParser(_pConnection->getDriver()->getComponentContext()), + m_aSQLIterator(_pConnection, _pConnection->createCatalog()->getTables(), m_aParser ), + m_pParseTree(nullptr), + m_pConnection(_pConnection) +{ + m_pConnection->acquire(); +} + +MacabCommonStatement::~MacabCommonStatement() +{ +} + +void MacabCommonStatement::resetParameters() const +{ +} + +void MacabCommonStatement::getNextParameter(OUString &) const +{ + impl_throwError(STR_PARA_ONLY_PREPARED); +} + +MacabCondition *MacabCommonStatement::analyseWhereClause(const OSQLParseNode *pParseNode) const +{ + if (pParseNode->count() == 3) + { + const OSQLParseNode *pLeft = pParseNode->getChild(0), + *pMiddle = pParseNode->getChild(1), + *pRight = pParseNode->getChild(2); + + // WHERE ( ... ) ? + if (SQL_ISPUNCTUATION(pLeft, "(") && SQL_ISPUNCTUATION(pRight, ")")) + { + return analyseWhereClause(pMiddle); + } + else if (SQL_ISRULE(pParseNode, comparison_predicate)) + { + if (pLeft->isToken() && pRight->isToken()) + { + switch (pMiddle->getNodeType()) + { + case SQLNodeType::Equal: + // WHERE 0 = 1 + return new MacabConditionConstant(pLeft->getTokenValue() == pRight->getTokenValue()); + + case SQLNodeType::NotEqual: + // WHERE 0 <> 1 + // (might not be correct SQL... don't care, handling anyway) + return new MacabConditionConstant(pLeft->getTokenValue() != pRight->getTokenValue()); + + default: + break; + } + } + else if (SQL_ISRULE(pLeft, column_ref)) + { + OUString sColumnName, + sTableRange; + + m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange); + + if (pRight->isToken() || SQL_ISRULE(pRight, parameter)) + { + OUString sMatchString; + + if (pRight->isToken()) // WHERE Name = 'Doe' + sMatchString = pRight->getTokenValue(); + else if (SQL_ISRULE(pRight, parameter)) // WHERE Name = ? + getNextParameter(sMatchString); + + switch (pMiddle->getNodeType()) + { + case SQLNodeType::Equal: + // WHERE Name = 'Smith' + return new MacabConditionEqual(m_pHeader, sColumnName, sMatchString); + + case SQLNodeType::NotEqual: + // WHERE Name <> 'Jones' + return new MacabConditionDifferent(m_pHeader, sColumnName, sMatchString); + + default: + break; + } + } + } + } + else if (SQL_ISRULE(pParseNode, search_condition)) + { + if (SQL_ISTOKEN(pMiddle, OR)) + { + // WHERE Name = 'Smith' OR Name = 'Jones' + return new MacabConditionOr( + analyseWhereClause(pLeft), + analyseWhereClause(pRight)); + } + } + else if (SQL_ISRULE(pParseNode, boolean_term)) + { + if (SQL_ISTOKEN(pMiddle, AND)) + { + // WHERE Name = 'Smith' AND "Given Name" = 'Peter' + return new MacabConditionAnd( + analyseWhereClause(pLeft), + analyseWhereClause(pRight)); + } + } + } + else if (SQL_ISRULE(pParseNode, test_for_null) || SQL_ISRULE(pParseNode, like_predicate)) + { + const OSQLParseNode *pLeft = pParseNode->getChild(0); + const OSQLParseNode* pPart2 = pParseNode->getChild(1); + const OSQLParseNode *pMiddleLeft = pPart2->getChild(0), + *pMiddleRight = pPart2->getChild(1), + *pRight = pPart2->getChild(2); + + if (SQL_ISRULE(pParseNode, test_for_null)) + { + if (SQL_ISRULE(pLeft, column_ref) && + SQL_ISTOKEN(pMiddleLeft, IS) && + SQL_ISTOKEN(pRight, NULL)) + { + OUString sColumnName, + sTableRange; + + m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange); + + if (SQL_ISTOKEN(pMiddleRight, NOT)) + { + // WHERE "Mobile Phone" IS NOT NULL + return new MacabConditionNotNull(m_pHeader, sColumnName); + } + else + { + // WHERE "Mobile Phone" IS NULL + return new MacabConditionNull(m_pHeader, sColumnName); + } + } + } + else if (SQL_ISRULE(pParseNode, like_predicate)) + { + if (SQL_ISRULE(pLeft, column_ref)) + { + OUString sColumnName, + sTableRange; + + m_aSQLIterator.getColumnRange(pLeft, sColumnName, sTableRange); + + if (pMiddleRight->isToken() || SQL_ISRULE(pMiddleRight, parameter)) + { + OUString sMatchString; + + if (pMiddleRight->isToken()) // WHERE Name LIKE 'Sm%' + sMatchString = pMiddleRight->getTokenValue(); + else if (SQL_ISRULE(pMiddleRight, parameter)) // WHERE Name LIKE ? + getNextParameter(sMatchString); + + return new MacabConditionSimilar(m_pHeader, sColumnName, sMatchString); + } + } + } + } + impl_throwError(STR_QUERY_TOO_COMPLEX); + // Unreachable: + OSL_ASSERT(false); + return nullptr; +} + +MacabOrder *MacabCommonStatement::analyseOrderByClause(const OSQLParseNode *pParseNode) const +{ + if (SQL_ISRULE(pParseNode, ordering_spec_commalist)) + { + MacabComplexOrder *list = new MacabComplexOrder(); + sal_uInt32 n = pParseNode->count(); + + // Iterate through the ordering columns + for (sal_uInt32 i = 0; i < n; i++) + { + list->addOrder + (analyseOrderByClause(pParseNode->getChild(i))); + } + + return list; + } + else if (SQL_ISRULE(pParseNode, ordering_spec)) + { + if (pParseNode->count() == 2) + { + OSQLParseNode* pColumnRef = pParseNode->getChild(0); + OSQLParseNode* pAscendingDescending = pParseNode->getChild(1); + + if (SQL_ISRULE(pColumnRef, column_ref)) + { + if (pColumnRef->count() == 3) + pColumnRef = pColumnRef->getChild(2); + + if (pColumnRef->count() == 1) + { + OUString sColumnName = + pColumnRef->getChild(0)->getTokenValue(); + bool bAscending = + !SQL_ISTOKEN(pAscendingDescending, DESC); + + return new MacabSimpleOrder(m_pHeader, sColumnName, bAscending); + } + } + } + } + impl_throwError(STR_QUERY_TOO_COMPLEX); + // Unreachable: + OSL_ASSERT(false); + return nullptr; +} + +OUString MacabCommonStatement::getTableName() const +{ + const OSQLTables& xTabs = m_aSQLIterator.getTables(); + + if( xTabs.empty() ) + return OUString(); + + // can only deal with one table at a time + if(xTabs.size() > 1 || m_aSQLIterator.hasErrors() ) + return OUString(); + + return xTabs.begin()->first; +} + +void MacabCommonStatement::setMacabFields(MacabResultSet *pResult) const +{ + ::rtl::Reference<connectivity::OSQLColumns> xColumns; // selected columns + MacabResultSetMetaData *pMeta; // meta information - holds the list of AddressBook fields + + xColumns = m_aSQLIterator.getSelectColumns(); + if (!xColumns.is()) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString( + STR_INVALID_COLUMN_SELECTION + ) ); + ::dbtools::throwGenericSQLException(sError,nullptr); + } + pMeta = static_cast<MacabResultSetMetaData *>(pResult->getMetaData().get()); + pMeta->setMacabFields(xColumns); +} + +void MacabCommonStatement::selectRecords(MacabResultSet *pResult) const +{ + const OSQLParseNode *pParseNode; + + pParseNode = m_aSQLIterator.getWhereTree(); + if (pParseNode != nullptr) + { + if (SQL_ISRULE(pParseNode, where_clause)) + { + resetParameters(); + pParseNode = pParseNode->getChild(1); + MacabCondition *pCondition = analyseWhereClause(pParseNode); + if (pCondition->isAlwaysTrue()) + pResult->allMacabRecords(); + else + pResult->someMacabRecords(pCondition); + delete pCondition; + return; + } + } + + // no WHERE clause: get all rows + pResult->allMacabRecords(); +} + +void MacabCommonStatement::sortRecords(MacabResultSet *pResult) const +{ + const OSQLParseNode *pParseNode; + + pParseNode = m_aSQLIterator.getOrderTree(); + if (pParseNode != nullptr) + { + if (SQL_ISRULE(pParseNode, opt_order_by_clause)) + { + pParseNode = pParseNode->getChild(2); + MacabOrder *pOrder = analyseOrderByClause(pParseNode); + pResult->sortMacabRecords(pOrder); + delete pOrder; + } + } +} + +Any SAL_CALL MacabCommonStatement::queryInterface( const Type & rType ) +{ + Any aRet = MacabCommonStatement_BASE::queryInterface(rType); + if (!aRet.hasValue()) + aRet = OPropertySetHelper::queryInterface(rType); + return aRet; +} + +Sequence< Type > SAL_CALL MacabCommonStatement::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return comphelper::concatSequences(aTypes.getTypes(),MacabCommonStatement_BASE::getTypes()); +} + +void SAL_CALL MacabCommonStatement::cancel( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + checkDisposed(rBHelper.bDisposed); + // cancel the current sql statement +} + +void SAL_CALL MacabCommonStatement::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + } + dispose(); +} + +sal_Bool SAL_CALL MacabCommonStatement::execute( + const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + Reference< XResultSet > xRS = executeQuery(sql); + + return xRS.is(); +} + +Reference< XResultSet > SAL_CALL MacabCommonStatement::executeQuery( + const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + MacabResultSet* pResult = new MacabResultSet(this); + Reference< XResultSet > xRS = pResult; + OUString aErr; + + m_pParseTree = m_aParser.parseTree(aErr, sql).release(); + if (m_pParseTree == nullptr) + throw SQLException(aErr, *this, aErr, 0, Any()); + + m_aSQLIterator.setParseTree(m_pParseTree); + m_aSQLIterator.traverseAll(); + switch (m_aSQLIterator.getStatementType()) + { + case OSQLStatementType::Select: + { + OUString sTableName = getTableName(); // FROM which table ? + if (sTableName.getLength() != 0) // a match + { + MacabRecords *aRecords; + aRecords = m_pConnection->getAddressBook()->getMacabRecords(sTableName); + + // In case, somehow, we don't have anything with the name m_sTableName + if(aRecords == nullptr) + { + impl_throwError(STR_NO_TABLE); + } + else + { + m_pHeader = aRecords->getHeader(); + + pResult->setTableName(sTableName); + + setMacabFields(pResult); // SELECT which columns ? + selectRecords(pResult); // WHERE which condition ? + sortRecords(pResult); // ORDER BY which columns ? + } +// To be continued: DISTINCT +// etc... + } + } + break; + + default: +// To be continued: UPDATE +// DELETE +// etc... + impl_throwError(STR_QUERY_TOO_COMPLEX); + } + + m_xResultSet = Reference<XResultSet>(pResult); + return xRS; +} + +Reference< XConnection > SAL_CALL MacabCommonStatement::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + // just return our connection here + return m_pConnection; +} + +sal_Int32 SAL_CALL MacabCommonStatement::executeUpdate( const OUString& ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + // the return values gives information about how many rows are affected by executing the sql statement + return 0; +} + +Any SAL_CALL MacabCommonStatement::getWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return makeAny(m_aLastWarning); +} + +void SAL_CALL MacabCommonStatement::clearWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + m_aLastWarning = SQLWarning(); +} + +::cppu::IPropertyArrayHelper* MacabCommonStatement::createArrayHelper( ) const +{ + // this properties are defined by the service statement + // they must be in alphabetic order + Sequence< Property > aProps(10); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper & MacabCommonStatement::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool MacabCommonStatement::convertFastPropertyValue( + Any &, + Any &, + sal_Int32, + const Any&) +{ + // here we have to try to convert + return false; +} + +void MacabCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any&) +{ + // set the value to whatever is necessary + switch (nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + case PROPERTY_ID_USEBOOKMARKS: + default: + ; + } +} + +void MacabCommonStatement::getFastPropertyValue(Any&,sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + case PROPERTY_ID_USEBOOKMARKS: + default: + ; + } +} + +void SAL_CALL MacabCommonStatement::acquire() throw() +{ + MacabCommonStatement_BASE::acquire(); +} + +void SAL_CALL MacabCommonStatement::release() throw() +{ + MacabCommonStatement_BASE::release(); +} + +Reference< css::beans::XPropertySetInfo > SAL_CALL MacabCommonStatement::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +MacabStatement::MacabStatement(MacabConnection* _pConnection) + : MacabStatement_BASE(_pConnection) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabStatement.hxx b/connectivity/source/drivers/macab/MacabStatement.hxx new file mode 100644 index 000000000..3c8187016 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabStatement.hxx @@ -0,0 +1,174 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABSTATEMENT_HXX + +#include "MacabConnection.hxx" +#include "MacabHeader.hxx" +#include <connectivity/sqliterator.hxx> +#include <connectivity/sqlparse.hxx> +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <comphelper/proparrhlp.hxx> + +namespace connectivity +{ + namespace macab + { + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement, + css::sdbc::XWarningsSupplier, + css::util::XCancellable, + css::sdbc::XCloseable> MacabCommonStatement_BASE; + + + // Class MacabCommonStatement + // is a base class for the normal statement and for the prepared statement + + class MacabCommonStatement : public cppu::BaseMutex, + public MacabCommonStatement_BASE, + public ::cppu::OPropertySetHelper, + public comphelper::OPropertyArrayUsageHelper<MacabCommonStatement> + + { + css::sdbc::SQLWarning m_aLastWarning; + + protected: + connectivity::OSQLParser m_aParser; + connectivity::OSQLParseTreeIterator m_aSQLIterator; + connectivity::OSQLParseNode* m_pParseTree; + MacabConnection* m_pConnection; // The owning Connection object + MacabHeader* m_pHeader; // The header of the address book on which to run queries (provided by m_pConnection) + css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created + + + protected: + /// @throws css::sdbc::SQLException + class MacabCondition *analyseWhereClause( + const OSQLParseNode *pParseNode) const; + /// @throws css::sdbc::SQLException + class MacabOrder *analyseOrderByClause( + const OSQLParseNode *pParseNode) const; + OUString getTableName( ) const; + /// @throws css::sdbc::SQLException + void setMacabFields(class MacabResultSet *pResult) const; + /// @throws css::sdbc::SQLException + void selectRecords(MacabResultSet *pResult) const; + /// @throws css::sdbc::SQLException + void sortRecords(MacabResultSet *pResult) const; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle) const override; + + /// @throws css::sdbc::SQLException + virtual void resetParameters() const; + /// @throws css::sdbc::SQLException + virtual void getNextParameter(OUString &rParameter) const; + virtual ~MacabCommonStatement() override; + + public: + using MacabCommonStatement_BASE::rBHelper; + + explicit MacabCommonStatement(MacabConnection *_pConnection); + using MacabCommonStatement_BASE::operator css::uno::Reference< css::uno::XInterface >; + + // OComponentHelper + using MacabCommonStatement_BASE::disposing; + + // XInterface + virtual void SAL_CALL release() throw() override; + virtual void SAL_CALL acquire() throw() override; + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & rType + ) override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( + ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( + ) override; + + // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( + const OUString& sql ) override; + virtual sal_Int32 SAL_CALL executeUpdate( + const OUString& sql ) override; + virtual sal_Bool SAL_CALL execute( + const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( + ) override; + + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( + ) override; + virtual void SAL_CALL clearWarnings( + ) override; + + // XCancellable + virtual void SAL_CALL cancel( + ) override; + + // XCloseable + virtual void SAL_CALL close( + ) override; + + // other methods + MacabConnection* getOwnConnection() const { return m_pConnection; } + }; + + + // Class MacabStatement + + typedef ::cppu::ImplInheritanceHelper< + MacabCommonStatement, css::lang::XServiceInfo > MacabStatement_BASE; + + class MacabStatement : public MacabStatement_BASE + { + protected: + virtual ~MacabStatement() override { } + + public: + explicit MacabStatement(MacabConnection* _pConnection); + DECLARE_SERVICE_INFO(); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabTable.cxx b/connectivity/source/drivers/macab/MacabTable.cxx new file mode 100644 index 000000000..75da75bc1 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabTable.cxx @@ -0,0 +1,86 @@ +/* -*- 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 "MacabTable.hxx" +#include "MacabTables.hxx" +#include "MacabColumns.hxx" +#include "MacabCatalog.hxx" +#include <com/sun/star/sdbc/XRow.hpp> + +using namespace connectivity::macab; +using namespace connectivity; +using namespace ::comphelper; +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; + + +MacabTable::MacabTable( sdbcx::OCollection* _pTables, MacabConnection* _pConnection) + : MacabTable_TYPEDEF(_pTables, true), + m_pConnection(_pConnection) +{ + construct(); +} + +MacabTable::MacabTable( sdbcx::OCollection* _pTables, + MacabConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName + ) : MacabTable_TYPEDEF(_pTables,true, + Name, + Type, + Description, + SchemaName, + CatalogName), + m_pConnection(_pConnection) +{ + construct(); +} + +void MacabTable::refreshColumns() +{ + ::std::vector< OUString> aVector; + + if (!isNew()) + { + Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns( + Any(), m_SchemaName, m_Name, "%"); + + if (xResult.is()) + { + Reference< XRow > xRow(xResult, UNO_QUERY); + while (xResult->next()) + aVector.push_back(xRow->getString(4)); + } + } + + if (m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns = new MacabColumns(this,m_aMutex,aVector); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabTable.hxx b/connectivity/source/drivers/macab/MacabTable.hxx new file mode 100644 index 000000000..58e43175d --- /dev/null +++ b/connectivity/source/drivers/macab/MacabTable.hxx @@ -0,0 +1,60 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABTABLE_HXX + +#include "MacabConnection.hxx" +#include <connectivity/sdbcx/VTable.hxx> + +namespace connectivity +{ + namespace macab + { + typedef connectivity::sdbcx::OTable MacabTable_TYPEDEF; + + class MacabTable : public MacabTable_TYPEDEF + { + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + MacabConnection* m_pConnection; + + public: + MacabTable( sdbcx::OCollection* _pTables, MacabConnection* _pConnection); + MacabTable( sdbcx::OCollection* _pTables, + MacabConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description = OUString(), + const OUString& SchemaName = OUString(), + const OUString& CatalogName = OUString() + ); + + MacabConnection* getConnection() { return m_pConnection;} + + virtual void refreshColumns() override; + + OUString const & getTableName() const { return m_Name; } + OUString const & getSchema() const { return m_SchemaName; } + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabTables.cxx b/connectivity/source/drivers/macab/MacabTables.cxx new file mode 100644 index 000000000..c70aa87f8 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabTables.cxx @@ -0,0 +1,81 @@ +/* -*- 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 "MacabTables.hxx" +#include "MacabTable.hxx" +#include "MacabCatalog.hxx" +#include "MacabConnection.hxx" +#include <comphelper/types.hxx> +#include <com/sun/star/sdbc/XRow.hpp> + +using namespace connectivity::macab; +using namespace connectivity; +using namespace ::comphelper; +using namespace ::cppu; +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; + +sdbcx::ObjectType MacabTables::createObject(const OUString& _rName) +{ + OUString aName,aSchema; + aSchema = "%"; + aName = _rName; + + Sequence< OUString > aTypes { "%" }; + + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), aSchema, aName, aTypes); + + sdbcx::ObjectType xRet; + if (xResult.is()) + { + Reference< XRow > xRow(xResult, UNO_QUERY); + if (xResult->next()) // there can be only one table with this name + { + MacabTable* pRet = new MacabTable( + this, + static_cast<MacabCatalog&>(m_rParent).getConnection(), + aName, + xRow->getString(4), + xRow->getString(5), + ""); + xRet = pRet; + } + } + ::comphelper::disposeComponent(xResult); + + return xRet; +} + +void MacabTables::impl_refresh( ) +{ + static_cast<MacabCatalog&>(m_rParent).refreshTables(); +} + +void MacabTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/MacabTables.hxx b/connectivity/source/drivers/macab/MacabTables.hxx new file mode 100644 index 000000000..7e87a473a --- /dev/null +++ b/connectivity/source/drivers/macab/MacabTables.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABTABLES_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> + +namespace connectivity +{ + namespace macab + { + class MacabTables : public sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + + public: + MacabTables( + const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) + : sdbcx::OCollection(_rParent,true,_rMutex,_rVector), + m_xMetaData(_rMetaData) + { } + + virtual void disposing() override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABTABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/macab1.component b/connectivity/source/drivers/macab/macab1.component new file mode 100644 index 000000000..84d17a9cb --- /dev/null +++ b/connectivity/source/drivers/macab/macab1.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="macab" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.macab.Driver"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/macab/macabcondition.cxx b/connectivity/source/drivers/macab/macabcondition.cxx new file mode 100644 index 000000000..0d1d20227 --- /dev/null +++ b/connectivity/source/drivers/macab/macabcondition.cxx @@ -0,0 +1,242 @@ +/* -*- 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 "macabcondition.hxx" +#include "MacabHeader.hxx" +#include "MacabRecord.hxx" +#include <connectivity/CommonTools.hxx> + +using namespace ::connectivity::macab; +using namespace ::com::sun::star::sdbc; + +MacabCondition::~MacabCondition() +{ +} + +MacabConditionConstant::MacabConditionConstant(const bool bValue) + : MacabCondition(), + m_bValue(bValue) +{ +} + +bool MacabConditionConstant::isAlwaysTrue() const +{ + return m_bValue; +} + +bool MacabConditionConstant::isAlwaysFalse() const +{ + return !m_bValue; +} + +bool MacabConditionConstant::eval(const MacabRecord *) const +{ + return m_bValue; +} + +MacabConditionColumn::MacabConditionColumn(const MacabHeader *header, const OUString &sColumnName) + : MacabCondition(), + m_nFieldNumber(header->getColumnNumber(sColumnName)) +{ +} + +bool MacabConditionColumn::isAlwaysTrue() const +{ + // Sometimes true, sometimes false + return false; +} + +bool MacabConditionColumn::isAlwaysFalse() const +{ + // Sometimes true, sometimes false + return false; +} + +MacabConditionNull::MacabConditionNull(const MacabHeader *header, const OUString &sColumnName) + : MacabConditionColumn(header, sColumnName) +{ +} + +bool MacabConditionNull::eval(const MacabRecord *aRecord) const +{ + macabfield *aValue = aRecord->get(m_nFieldNumber); + + if(aValue == nullptr) + return true; + else if(aValue->value == nullptr) + return true; + else + return false; +} + +MacabConditionNotNull::MacabConditionNotNull(const MacabHeader *header, const OUString &sColumnName) + : MacabConditionColumn(header, sColumnName) +{ +} + +bool MacabConditionNotNull::eval(const MacabRecord *aRecord) const +{ + macabfield *aValue = aRecord->get(m_nFieldNumber); + + if(aValue == nullptr) + return false; + else if(aValue->value == nullptr) + return false; + else + return true; +} + +MacabConditionCompare::MacabConditionCompare(const MacabHeader *header, const OUString &sColumnName, const OUString &sMatchString) + : MacabConditionColumn(header, sColumnName), + m_sMatchString(sMatchString) +{ +} + +MacabConditionEqual::MacabConditionEqual(const MacabHeader *header, const OUString &sColumnName, const OUString &sMatchString) + : MacabConditionCompare(header, sColumnName, sMatchString) +{ +} + +bool MacabConditionEqual::eval(const MacabRecord *aRecord) const +{ + macabfield *aValue = aRecord->get(m_nFieldNumber); + + if(aValue == nullptr) + return false; + + macabfield *aValue2 = MacabRecord::createMacabField(m_sMatchString,aValue->type); + + if(aValue2 == nullptr) + return false; + + sal_Int32 nReturn = MacabRecord::compareFields(aValue, aValue2); + + delete aValue2; + return nReturn == 0; +} + +MacabConditionDifferent::MacabConditionDifferent(const MacabHeader *header, const OUString &sColumnName, const OUString &sMatchString) + : MacabConditionCompare(header, sColumnName, sMatchString) +{ +} + +bool MacabConditionDifferent::eval(const MacabRecord *aRecord) const +{ + macabfield *aValue = aRecord->get(m_nFieldNumber); + + if(aValue == nullptr) + return false; + + macabfield *aValue2 = MacabRecord::createMacabField(m_sMatchString,aValue->type); + + if(aValue2 == nullptr) + return false; + + sal_Int32 nReturn = MacabRecord::compareFields(aValue, aValue2); + + delete aValue2; + return nReturn != 0; +} + +MacabConditionSimilar::MacabConditionSimilar(const MacabHeader *header, const OUString &sColumnName, const OUString &sMatchString) + : MacabConditionCompare(header, sColumnName, sMatchString) +{ +} + +bool MacabConditionSimilar::eval(const MacabRecord *aRecord) const +{ + macabfield *aValue = aRecord->get(m_nFieldNumber); + + if(aValue == nullptr) + return false; + + OUString sName = MacabRecord::fieldToString(aValue); + + return match(m_sMatchString, sName, '\0'); +} + +MacabConditionBoolean::MacabConditionBoolean(MacabCondition *pLeft, MacabCondition *pRight) + : MacabCondition(), + m_pLeft(pLeft), + m_pRight(pRight) +{ +} + +MacabConditionBoolean::~MacabConditionBoolean() +{ + delete m_pLeft; + delete m_pRight; +} + +MacabConditionOr::MacabConditionOr(MacabCondition *pLeft, MacabCondition *pRight) + : MacabConditionBoolean(pLeft, pRight) +{ +} + +bool MacabConditionOr::isAlwaysTrue() const +{ + return m_pLeft->isAlwaysTrue() || m_pRight->isAlwaysTrue(); +} + +bool MacabConditionOr::isAlwaysFalse() const +{ + return m_pLeft->isAlwaysFalse() && m_pRight->isAlwaysFalse(); +} + +bool MacabConditionOr::eval(const MacabRecord *aRecord) const +{ + // We avoid evaluating terms as much as we can + if (m_pLeft->isAlwaysTrue() || m_pRight->isAlwaysTrue()) return true; + if (m_pLeft->isAlwaysFalse() && m_pRight->isAlwaysFalse()) return false; + + if (m_pLeft->eval(aRecord)) return true; + if (m_pRight->eval(aRecord)) return true; + + return false; +} + +MacabConditionAnd::MacabConditionAnd(MacabCondition *pLeft, MacabCondition *pRight) + : MacabConditionBoolean(pLeft, pRight) +{ +} + +bool MacabConditionAnd::isAlwaysTrue() const +{ + return m_pLeft->isAlwaysTrue() && m_pRight->isAlwaysTrue(); +} + +bool MacabConditionAnd::isAlwaysFalse() const +{ + return m_pLeft->isAlwaysFalse() || m_pRight->isAlwaysFalse(); +} + +bool MacabConditionAnd::eval(const MacabRecord *aRecord) const +{ + // We avoid evaluating terms as much as we can + if (m_pLeft->isAlwaysFalse() || m_pRight->isAlwaysFalse()) return false; + if (m_pLeft->isAlwaysTrue() && m_pRight->isAlwaysTrue()) return true; + + if (!m_pLeft->eval(aRecord)) return false; + if (!m_pRight->eval(aRecord)) return false; + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/macabcondition.hxx b/connectivity/source/drivers/macab/macabcondition.hxx new file mode 100644 index 000000000..15eb853b1 --- /dev/null +++ b/connectivity/source/drivers/macab/macabcondition.hxx @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCONDITION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCONDITION_HXX + +#include "MacabHeader.hxx" +#include "MacabRecord.hxx" + +#include <connectivity/dbexception.hxx> + +namespace connectivity +{ + namespace macab + { + +class MacabCondition +{ + public: + virtual ~MacabCondition(); + virtual bool isAlwaysTrue() const = 0; + virtual bool isAlwaysFalse() const = 0; + virtual bool eval(const MacabRecord *aRecord) const = 0; +}; + +class MacabConditionConstant : public MacabCondition +{ + protected: + bool m_bValue; + + public: + explicit MacabConditionConstant(const bool bValue); + virtual bool isAlwaysTrue() const override; + virtual bool isAlwaysFalse() const override; + virtual bool eval(const MacabRecord *aRecord) const override; +}; + +class MacabConditionColumn : public MacabCondition +{ + protected: + sal_Int32 m_nFieldNumber; + + public: + /// @throws css::sdbc::SQLException + MacabConditionColumn( + const MacabHeader *header, + const OUString &sColumnName); + virtual bool isAlwaysTrue() const override; + virtual bool isAlwaysFalse() const override; +}; + +class MacabConditionNull : public MacabConditionColumn +{ + public: + /// @throws css::sdbc::SQLException + MacabConditionNull( + const MacabHeader *header, + const OUString &sColumnName); + virtual bool eval(const MacabRecord *aRecord) const override; +}; + +class MacabConditionNotNull : public MacabConditionColumn +{ + public: + /// @throws css::sdbc::SQLException + MacabConditionNotNull( + const MacabHeader *header, + const OUString &sColumnName); + virtual bool eval(const MacabRecord *aRecord) const override; +}; + +class MacabConditionCompare : public MacabConditionColumn +{ + protected: + const OUString m_sMatchString; + + public: + /// @throws css::sdbc::SQLException + MacabConditionCompare( + const MacabHeader *header, + const OUString &sColumnName, + const OUString &sMatchString); +}; + +class MacabConditionEqual : public MacabConditionCompare +{ + public: + /// @throws css::sdbc::SQLException + MacabConditionEqual( + const MacabHeader *header, + const OUString &sColumnName, + const OUString &sMatchString); + virtual bool eval(const MacabRecord *aRecord) const override; +}; + +class MacabConditionDifferent : public MacabConditionCompare +{ + public: + /// @throws css::sdbc::SQLException + MacabConditionDifferent( + const MacabHeader *header, + const OUString &sColumnName, + const OUString &sMatchString); + virtual bool eval(const MacabRecord *aRecord) const override; +}; + +class MacabConditionSimilar : public MacabConditionCompare +{ + public: + /// @throws css::sdbc::SQLException + MacabConditionSimilar( + const MacabHeader *header, + const OUString &sColumnName, + const OUString &sMatchString); + virtual bool eval(const MacabRecord *aRecord) const override; +}; + +class MacabConditionBoolean : public MacabCondition +{ + protected: + MacabCondition *m_pLeft, *m_pRight; + + public: + MacabConditionBoolean(MacabCondition *pLeft, MacabCondition *pRight); + virtual ~MacabConditionBoolean() override; +}; + +class MacabConditionOr : public MacabConditionBoolean +{ + public: + MacabConditionOr(MacabCondition *pLeft, MacabCondition *pRight); + virtual bool isAlwaysTrue() const override; + virtual bool isAlwaysFalse() const override; + virtual bool eval(const MacabRecord *aRecord) const override; +}; + +class MacabConditionAnd : public MacabConditionBoolean +{ + public: + MacabConditionAnd(MacabCondition *pLeft, MacabCondition *pRight); + virtual bool isAlwaysTrue() const override; + virtual bool isAlwaysFalse() const override; + virtual bool eval(const MacabRecord *aRecord) const override; +}; + + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABCONDITION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/macaborder.cxx b/connectivity/source/drivers/macab/macaborder.cxx new file mode 100644 index 000000000..aaef39ef6 --- /dev/null +++ b/connectivity/source/drivers/macab/macaborder.cxx @@ -0,0 +1,75 @@ +/* -*- 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 "macaborder.hxx" +#include "MacabHeader.hxx" +#include "MacabRecord.hxx" + +using namespace ::connectivity::macab; + +MacabOrder::~MacabOrder() +{ +} + +MacabSimpleOrder::MacabSimpleOrder(MacabHeader const *header, OUString const &sColumnName, bool bAscending) + : MacabOrder(), + m_nFieldNumber(header->getColumnNumber(sColumnName)), + m_bAscending(bAscending) +{ +} + +sal_Int32 MacabSimpleOrder::compare(const MacabRecord *record1, const MacabRecord *record2) const +{ + sal_Int32 result; + + result = MacabRecord::compareFields(record1->get(m_nFieldNumber), record2->get(m_nFieldNumber)); + + if (!m_bAscending) result = -result; + + return result; +} + +MacabComplexOrder::MacabComplexOrder() + : MacabOrder(), + m_aOrders() +{ +} + +MacabComplexOrder::~MacabComplexOrder() +{ +} + +void MacabComplexOrder::addOrder(MacabOrder *pOrder) +{ + m_aOrders.emplace_back(pOrder); +} + +sal_Int32 MacabComplexOrder::compare(const MacabRecord *record1, const MacabRecord *record2) const +{ + for (auto const & p: m_aOrders) + { + sal_Int32 result = p->compare(record1, record2); + + if (result) return result; + } + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/macaborder.hxx b/connectivity/source/drivers/macab/macaborder.hxx new file mode 100644 index 000000000..de7a2ed7c --- /dev/null +++ b/connectivity/source/drivers/macab/macaborder.hxx @@ -0,0 +1,69 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABORDER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABORDER_HXX + +#include <rtl/ustring.hxx> +#include "MacabHeader.hxx" +#include "MacabRecord.hxx" + +#include <memory> +#include <vector> + +namespace connectivity +{ + namespace macab + { + class MacabOrder + { + public: + virtual ~MacabOrder(); + + virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const = 0; + }; + + class MacabSimpleOrder : public MacabOrder + { + sal_Int32 m_nFieldNumber; + bool m_bAscending; + + public: + MacabSimpleOrder(MacabHeader const *header, OUString const &sColumnName, bool bAscending); + + virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const override; + }; + + class MacabComplexOrder : public MacabOrder + { + std::vector<std::unique_ptr<MacabOrder>> m_aOrders; + + public: + MacabComplexOrder(); + virtual ~MacabComplexOrder() override; + + void addOrder(MacabOrder *pOrder); + virtual sal_Int32 compare(const MacabRecord *record1, const MacabRecord *record2) const override; + }; + } +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/macab/macabutilities.hxx b/connectivity/source/drivers/macab/macabutilities.hxx new file mode 100644 index 000000000..c384604e3 --- /dev/null +++ b/connectivity/source/drivers/macab/macabutilities.hxx @@ -0,0 +1,143 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABUTILITIES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MACAB_MACABUTILITIES_HXX + +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/sdbc/DataType.hpp> + +#include <time.h> +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> + +namespace connectivity +{ + namespace macab + { + + inline OUString CFStringToOUString(const CFStringRef sOrig) + { + /* Copied all-but directly from code by Florian Heckl in + * cws_src680_aquafilepicker01 + * File was: fpicker/source/aqua/CFStringUtilities + * I only removed commented debugging lines and changed variable + * names. + */ + if (nullptr == sOrig) { + return OUString(); + } + + CFRetain(sOrig); + CFIndex nStringLength = CFStringGetLength(sOrig); + + UniChar unichars[nStringLength+1]; + + //'close' the string buffer correctly + unichars[nStringLength] = '\0'; + + CFStringGetCharacters (sOrig, CFRangeMake(0,nStringLength), unichars); + CFRelease(sOrig); + + return OUString(reinterpret_cast<sal_Unicode *>(unichars)); + } + + + inline CFStringRef OUStringToCFString(const OUString& aString) + { + /* Copied directly from code by Florian Heckl in + * cws_src680_aquafilepicker01 + * File was: fpicker/source/aqua/CFStringUtilities + */ + + CFStringRef ref = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<UniChar const *>(aString.getStr()), aString.getLength()); + + return ref; + } + + + inline css::util::DateTime CFDateToDateTime(const CFDateRef _cfDate) + { + /* Carbon can give us the time since 2001 of any CFDateRef, + * and it also stores the time since 1970 as a constant, + * basically allowing us to get the unixtime of any + * CFDateRef. From there, it is just a matter of choosing what + * we want to do with it. + */ + css::util::DateTime nRet; + double timeSince2001 = CFDateGetAbsoluteTime(_cfDate); + time_t unixtime = timeSince2001+kCFAbsoluteTimeIntervalSince1970; + struct tm *ptm = localtime(&unixtime); + nRet.Year = ptm->tm_year+1900; + nRet.Month = ptm->tm_mon+1; + nRet.Day = ptm->tm_mday; + nRet.Hours = ptm->tm_hour; + nRet.Minutes = ptm->tm_min; + nRet.Seconds = ptm->tm_sec; + nRet.NanoSeconds = 0; + return nRet; + } + + + inline OUString fixLabel(const OUString& _originalLabel) + { + /* Get the length, and make sure that there is actually a string + * here. + */ + if(_originalLabel.startsWith("_$!<")) + { + return _originalLabel.copy(4,_originalLabel.getLength()-8); + } + + return _originalLabel; + } + + + inline sal_Int32 ABTypeToDataType(const ABPropertyType _abType) + { + sal_Int32 dataType; + switch(_abType) + { + case kABStringProperty: + dataType = css::sdbc::DataType::CHAR; + break; + case kABDateProperty: + dataType = css::sdbc::DataType::TIMESTAMP; + break; + case kABIntegerProperty: + dataType = css::sdbc::DataType::INTEGER; + break; + case kABRealProperty: + dataType = css::sdbc::DataType::FLOAT; + break; + default: + dataType = -1; + } + return dataType; + } + + void impl_throwError(const char* pErrorId); + } +} + +#endif // _ CONNECTIVITY_MACAB_UTILITIES_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MCatalog.cxx b/connectivity/source/drivers/mork/MCatalog.cxx new file mode 100644 index 000000000..743d1e5ab --- /dev/null +++ b/connectivity/source/drivers/mork/MCatalog.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 "MCatalog.hxx" +#include "MConnection.hxx" +#include "MTables.hxx" + +#include <com/sun/star/sdbc/XRow.hpp> + + +using namespace connectivity::mork; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; + + +OCatalog::OCatalog(OConnection* _pCon) : connectivity::sdbcx::OCatalog(_pCon) + ,m_pConnection(_pCon) +{ +// osl_atomic_increment( &m_refCount ); +// refreshTables(); +// refreshViews(); +// refreshGroups(); +// refreshUsers(); +// osl_atomic_decrement( &m_refCount ); +} + +void OCatalog::refreshTables() +{ + ::std::vector< OUString> aVector; + Sequence< OUString > aTypes { "%" }; + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(), + "%", "%", aTypes); + + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + OUString aName; + while(xResult->next()) + { + aName = xRow->getString(3); + aVector.push_back(aName); + } + } + if(m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset( new OTables(m_xMetaData,*this,m_aMutex,aVector) ); +} + +void OCatalog::refreshViews() +{ +} + +void OCatalog::refreshGroups() +{ +} + +void OCatalog::refreshUsers() +{ +} + + +// XTablesSupplier +Reference< XNameAccess > SAL_CALL OCatalog::getTables( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + try + { + if(!m_pTables || OConnection::getForceLoadTables()) + refreshTables(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pTables.get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MCatalog.hxx b/connectivity/source/drivers/mork/MCatalog.hxx new file mode 100644 index 000000000..170809f7c --- /dev/null +++ b/connectivity/source/drivers/mork/MCatalog.hxx @@ -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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCATALOG_HXX + +#include <sdbcx/VCatalog.hxx> + +namespace connectivity +{ + namespace mork + { + // please don't name the class the same name as in another namespaces + // some compilers have problems with this task as I noticed on windows + class OConnection; + class OCatalog : public connectivity::sdbcx::OCatalog + { + OConnection* m_pConnection; // used to get the metadata + + public: + // implementation of the pure virtual methods + virtual void refreshTables() override; + virtual void refreshViews() override ; + virtual void refreshGroups() override; + virtual void refreshUsers() override ; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override; + public: + explicit OCatalog(OConnection* _pCon); + + OConnection* getConnection() const { return m_pConnection; } + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MColumnAlias.cxx b/connectivity/source/drivers/mork/MColumnAlias.cxx new file mode 100644 index 000000000..b320d8c45 --- /dev/null +++ b/connectivity/source/drivers/mork/MColumnAlias.cxx @@ -0,0 +1,133 @@ +/* -*- 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 "MColumnAlias.hxx" + +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <officecfg/Office/DataAccess.hxx> + +#include <osl/diagnose.h> +#include <sal/log.hxx> + +#include <algorithm> + +using namespace ::connectivity::mork; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + + +OColumnAlias::OColumnAlias( const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB ) +{ + static const char* s_pProgrammaticNames[] = + { + "FirstName", + "LastName", + "DisplayName", + "NickName", + "PrimaryEmail", + "SecondEmail", + "PreferMailFormat", + "WorkPhone", + "HomePhone", + "FaxNumber", + "PagerNumber", + "CellularNumber", + "HomeAddress", + "HomeAddress2", + "HomeCity", + "HomeState", + "HomeZipCode", + "HomeCountry", + "WorkAddress", + "WorkAddress2", + "WorkCity", + "WorkState", + "WorkZipCode", + "WorkCountry", + "JobTitle", + "Department", + "Company", + "WebPage1", + "WebPage2", + "BirthYear", + "BirthMonth", + "BirthDay", + "Custom1", + "Custom2", + "Custom3", + "Custom4", + "Notes", + }; + + for ( size_t i = 0; i < SAL_N_ELEMENTS( s_pProgrammaticNames ); ++i ) + m_aAliasMap[ OUString::createFromAscii( s_pProgrammaticNames[i] ) ] = AliasEntry( s_pProgrammaticNames[i], i ); + + initialize( _rxORB ); +} + + +void OColumnAlias::initialize( const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB ) +{ + Reference< XNameAccess > xAliasesNode( + officecfg::Office::DataAccess::DriverSettings:: + com_sun_star_comp_sdbc_MozabDriver::ColumnAliases::get( + comphelper::getComponentContext(_rxORB)), + UNO_QUERY_THROW); + const Sequence< OUString > aProgrammaticNames(xAliasesNode->getElementNames()); + for (const auto& rProgrammaticName : aProgrammaticNames) { + OString sAsciiProgrammaticName( + OUStringToOString( + rProgrammaticName, RTL_TEXTENCODING_ASCII_US)); + auto j = std::find_if(m_aAliasMap.begin(), m_aAliasMap.end(), + [&sAsciiProgrammaticName](const AliasMap::value_type& rEntry) { + return rEntry.second.programmaticAsciiName == sAsciiProgrammaticName; }); + if (j != m_aAliasMap.end()) { + OUString sAssignedAlias; + xAliasesNode->getByName(rProgrammaticName) >>= + sAssignedAlias; + if (sAssignedAlias.isEmpty()) { + sAssignedAlias = rProgrammaticName; + } + AliasEntry entry(j->second); + m_aAliasMap.erase(j); + m_aAliasMap[sAssignedAlias] = entry; + } + else { + SAL_WARN( + "connectivity.mork", + "unknown programmatic name " << rProgrammaticName + <<" from configuration"); + } + } +} + + +OString OColumnAlias::getProgrammaticNameOrFallbackToUTF8Alias( const OUString& _rAlias ) const +{ + AliasMap::const_iterator pos = m_aAliasMap.find( _rAlias ); + if ( pos == m_aAliasMap.end() ) + { + OSL_FAIL( "OColumnAlias::getProgrammaticNameOrFallbackToUTF8Alias: no programmatic name for this alias!" ); + return OUStringToOString( _rAlias, RTL_TEXTENCODING_UTF8 ); + } + return pos->second.programmaticAsciiName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MColumnAlias.hxx b/connectivity/source/drivers/mork/MColumnAlias.hxx new file mode 100644 index 000000000..3900b324b --- /dev/null +++ b/connectivity/source/drivers/mork/MColumnAlias.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ + + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCOLUMNALIAS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCOLUMNALIAS_HXX + +#include <unotools/confignode.hxx> + +#include <unordered_map> + +namespace connectivity +{ + namespace mork + { + class OColumnAlias + { + public: + struct AliasEntry + { + OString programmaticAsciiName; + size_t columnPosition; + + AliasEntry() + :programmaticAsciiName() + ,columnPosition( 0 ) + { + } + AliasEntry( const char* _programmaticAsciiName, size_t _columnPosition ) + :programmaticAsciiName( _programmaticAsciiName ) + ,columnPosition( _columnPosition ) + { + } + }; + typedef std::unordered_map< OUString, AliasEntry > AliasMap; + + private: + AliasMap m_aAliasMap; + + public: + explicit OColumnAlias( const css::uno::Reference< css::lang::XMultiServiceFactory > & ); + + OString getProgrammaticNameOrFallbackToUTF8Alias( const OUString& _rAlias ) const; + + AliasMap::const_iterator begin() const { return m_aAliasMap.begin(); } + AliasMap::const_iterator end() const { return m_aAliasMap.end(); } + + + private: + void initialize( const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB ); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCOLUMNALIAS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MColumns.cxx b/connectivity/source/drivers/mork/MColumns.cxx new file mode 100644 index 000000000..c9163a6ab --- /dev/null +++ b/connectivity/source/drivers/mork/MColumns.cxx @@ -0,0 +1,80 @@ +/* -*- 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 "MColumns.hxx" +#include <com/sun/star/sdbc/XRow.hpp> +#include <connectivity/sdbcx/VColumn.hxx> + +using namespace connectivity::mork; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; + + +sdbcx::ObjectType OColumns::createObject(const OUString& _rName) +{ + const Any aCatalog; + const OUString sCatalogName; + const OUString sSchemaName(m_pTable->getSchema()); + const OUString sTableName(m_pTable->getTableName()); + Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns( + aCatalog, sSchemaName, sTableName, _rName); + + sdbcx::ObjectType xRet; + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + while(xResult->next()) + { + if(xRow->getString(4) == _rName) + { + sal_Int32 nType = xRow->getInt(5); + OUString sTypeName = xRow->getString(6); + sal_Int32 nPrec = xRow->getInt(7); + + OColumn* pRet = new OColumn(_rName, + sTypeName, + xRow->getString(13), + xRow->getString(12), + xRow->getInt(11), + nPrec, + xRow->getInt(9), + nType, + false,false,false,true, + sCatalogName, + sSchemaName, + sTableName); + xRet = pRet; + break; + } + } + } + + return xRet; +} + + +void OColumns::impl_refresh() +{ + m_pTable->refreshColumns(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MColumns.hxx b/connectivity/source/drivers/mork/MColumns.hxx new file mode 100644 index 000000000..b0774af27 --- /dev/null +++ b/connectivity/source/drivers/mork/MColumns.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCOLUMNS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include "MTable.hxx" + +namespace connectivity +{ + namespace mork + { + class OColumns final : public sdbcx::OCollection + { + OTable* m_pTable; + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + public: + OColumns( OTable* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector + ) : sdbcx::OCollection(*_pTable, true, _rMutex, _rVector) + ,m_pTable(_pTable) + {} + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MConnection.cxx b/connectivity/source/drivers/mork/MConnection.cxx new file mode 100644 index 000000000..e6658b6dc --- /dev/null +++ b/connectivity/source/drivers/mork/MConnection.cxx @@ -0,0 +1,377 @@ +/* -*- 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/. + */ + +#include "MConnection.hxx" +#include "MDriver.hxx" +#include "MDatabaseMetaData.hxx" +#include "MCatalog.hxx" +#include "MPreparedStatement.hxx" +#include "MorkParser.hxx" + +#include <connectivity/dbexception.hxx> +#include <sal/log.hxx> + +#include <strings.hrc> + +#include <com/sun/star/sdbc/TransactionIsolation.hpp> + +using namespace dbtools; + + +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::sdbcx; + + +namespace connectivity::mork { + +static const int defaultScope = 0x80; + + +OConnection::OConnection(MorkDriver* _pDriver) + :m_xDriver(_pDriver) + ,m_aColumnAlias( _pDriver->getFactory() ) +{ + m_pBook.reset( new MorkParser() ); + m_pHistory.reset( new MorkParser() ); +} + +OConnection::~OConnection() +{ + if(!isClosed()) + close(); + m_pBook.reset(); + m_pHistory.reset(); +} + +void OConnection::construct(const OUString& url) +{ + SAL_INFO("connectivity.mork", "=> OConnection::construct()" ); + // open file + setURL(url); + + // Skip 'sdbc:mozab: part of URL + + sal_Int32 nLen = url.indexOf(':'); + nLen = url.indexOf(':',nLen+1); + OSL_ENSURE( url.startsWith("sdbc:address:"), "OConnection::construct: invalid start of the URI - should never have survived XDriver::acceptsURL!" ); + + OUString aAddrbookURI(url.copy(nLen+1)); + // Get Scheme + nLen = aAddrbookURI.indexOf(':'); + OUString aAddrbookScheme; + if ( nLen == -1 ) + { + // There isn't any subschema: - but could be just subschema + if ( !aAddrbookURI.isEmpty() ) + { + aAddrbookScheme= aAddrbookURI; + } + else + { + SAL_WARN("connectivity.mork", "No subschema given!!!"); + throwGenericSQLException( STR_URI_SYNTAX_ERROR, *this ); + } + } + else + { + aAddrbookScheme = aAddrbookURI.copy(0, nLen); + } + + SAL_INFO("connectivity.mork", "URI = " << aAddrbookURI ); + SAL_INFO("connectivity.mork", "Scheme = " << aAddrbookScheme ); + + OUString abook; + OUString history; + const OUString UNITTEST_URL = "thunderbird:unittest:"; + sal_Int32 unittestIndex = url.indexOf(UNITTEST_URL); + + // production? + if (unittestIndex == -1) + { + OUString path = m_xDriver->getProfilePath(); + SAL_INFO("connectivity.mork", "ProfilePath: " << path); + abook = path + "/abook.mab"; + history = path + "/history.mab"; + SAL_INFO("connectivity.mork", "AdressbookPath (abook): " << abook); + SAL_INFO("connectivity.mork", "AdressbookPath (history): " << history); + } + else + { + abook = aAddrbookURI.replaceFirst(UNITTEST_URL, ""); + SAL_INFO("connectivity.mork", "unit test: " << abook); + } + + OString strPath = OUStringToOString(abook, RTL_TEXTENCODING_UTF8); + + // Open and parse mork file + if (!m_pBook->open(strPath.getStr())) + { + SAL_WARN("connectivity.mork", "Can not parse abook mork file: " << strPath); + const OUString sError( getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_LOAD_FILE, "$filename$", abook)); + ::dbtools::throwGenericSQLException( sError, *this ); + } + + // read history only in production + if (unittestIndex == -1) + { + strPath = OUStringToOString(history, RTL_TEXTENCODING_UTF8); + if (!m_pHistory->open(strPath.getStr())) + { + SAL_WARN("connectivity.mork", "Can not parse history mork file: " << strPath); + const OUString sError( getResources().getResourceStringWithSubstitution( + STR_COULD_NOT_LOAD_FILE, "$filename$", history)); + ::dbtools::throwGenericSQLException( sError, *this ); + } + } + + // check that we can retrieve the tables: + MorkTableMap *Tables = m_pBook->getTables( defaultScope ); + if (Tables) + { + // Iterate all tables + for ( const auto& rEntry : Tables->map ) + { + if ( 0 == rEntry.first ) continue; + SAL_INFO("connectivity.mork", "table->first : " << rEntry.first); + } + } + // check that we can retrieve the history tables: + MorkTableMap *Tables_hist = m_pHistory->getTables( defaultScope ); + if (Tables_hist) + { + // Iterate all tables + for ( const auto& rEntry : Tables_hist->map ) + { + if ( 0 == rEntry.first ) continue; + SAL_INFO("connectivity.mork", "table->first : " << rEntry.first); + } + } +} + +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.mork.OConnection", "com.sun.star.sdbc.Connection") + + +Reference< XStatement > SAL_CALL OConnection::createStatement( ) +{ + SAL_INFO("connectivity.mork", "=> OConnection::createStatement()" ); + + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // create a statement + // the statement can only be executed once + Reference< XStatement > xReturn = new OStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& _sSql ) +{ + SAL_INFO("connectivity.mork", "=> OConnection::prepareStatement()" ); + SAL_INFO("connectivity.mork", "OConnection::prepareStatement( " << _sSql << " )"); + + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // the pre + // create a statement + // the statement can only be executed more than once + OPreparedStatement* pPrepared = new OPreparedStatement(this,_sSql); + Reference< XPreparedStatement > xReturn = pPrepared; + pPrepared->lateInit(); + + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& _sSql ) +{ + SAL_INFO("connectivity.mork", "=> OConnection::prepareCall()" ); + SAL_INFO("connectivity.mork", "sql: " << _sSql); + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this ); + SAL_INFO("connectivity.mork", "OConnection::prepareCall( " << _sSql << " )"); + return nullptr; +} + +OUString SAL_CALL OConnection::nativeSQL( const OUString& _sSql ) +{ + SAL_INFO("connectivity.mork", "=> OConnection::nativeSQL()" ); + SAL_INFO("connectivity.mork", "sql: " << _sSql); + + ::osl::MutexGuard aGuard( m_aMutex ); + // when you need to transform SQL92 to you driver specific you can do it here + SAL_INFO("connectivity.mork", "OConnection::nativeSQL(" << _sSql << " )" ); + + return _sSql; +} + +void SAL_CALL OConnection::setAutoCommit( sal_Bool /*autoCommit*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setAutoCommit", *this ); +} + +sal_Bool SAL_CALL OConnection::getAutoCommit( ) +{ + // you have to distinguish which if you are in autocommit mode or not + // at normal case true should be fine here + + return true; +} + +void SAL_CALL OConnection::commit( ) +{ + // when you database does support transactions you should commit here +} + +void SAL_CALL OConnection::rollback( ) +{ + // same as commit but for the other case +} + +sal_Bool SAL_CALL OConnection::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent) + return OConnection_BASE::rBHelper.bDisposed; +} + +Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( ) +{ + SAL_INFO("connectivity.mork", "=> OConnection::getMetaData()" ); + + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // here we have to create the class with biggest interface + // The answer is 42 :-) + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new ODatabaseMetaData(this); // need the connection because it can return it + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +void SAL_CALL OConnection::setReadOnly( sal_Bool /*readOnly*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setReadOnly", *this ); +} + +sal_Bool SAL_CALL OConnection::isReadOnly( ) +{ + // return if your connection to readonly + return false; +} + +void SAL_CALL OConnection::setCatalog( const OUString& /*catalog*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setCatalog", *this ); +} + +OUString SAL_CALL OConnection::getCatalog( ) +{ + return OUString(); +} + +void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 /*level*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTransactionIsolation", *this ); +} + +sal_Int32 SAL_CALL OConnection::getTransactionIsolation( ) +{ + // please have a look at @see com.sun.star.sdbc.TransactionIsolation + return TransactionIsolation::NONE; +} + +Reference< css::container::XNameAccess > SAL_CALL OConnection::getTypeMap( ) +{ + // if your driver has special database types you can return it here + return nullptr; +} + +void SAL_CALL OConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this ); +} + +// XCloseable +void SAL_CALL OConnection::close( ) +{ + // we just dispose us + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + } + dispose(); +} + +// XWarningsSupplier +Any SAL_CALL OConnection::getWarnings( ) +{ + // when you collected some warnings -> return it + return Any(); +} + +void SAL_CALL OConnection::clearWarnings( ) +{ + // you should clear your collected warnings here +} + +void OConnection::disposing() +{ + // we noticed that we should be destroyed in near future so we have to dispose our statements + ::osl::MutexGuard aGuard(m_aMutex); + m_xCatalog.clear(); +} + +Reference< XTablesSupplier > OConnection::createCatalog() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XTablesSupplier > xTab = m_xCatalog; + if(!m_xCatalog.is()) + { + OCatalog *pCat = new OCatalog(this); + xTab = pCat; + m_xCatalog = xTab; + } + return xTab; +} + +void OConnection::throwSQLException( const ErrorDescriptor& _rError, const Reference< XInterface >& _rxContext ) +{ + if (_rError.getResId() != nullptr) + { + throwGenericSQLException( _rError.getResId(), _rxContext ); + OSL_FAIL( "OConnection::throwSQLException: unreachable (2)!" ); + } + + throwGenericSQLException( STR_UNSPECIFIED_ERROR, _rxContext ); +} + +void OConnection::throwSQLException( const char* pErrorResourceId, const Reference< XInterface >& _rxContext ) +{ + ErrorDescriptor aError; + aError.setResId(pErrorResourceId); + throwSQLException(aError, _rxContext); +} + +} // namespace connectivity::mork + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MConnection.hxx b/connectivity/source/drivers/mork/MConnection.hxx new file mode 100644 index 000000000..0bcb936bd --- /dev/null +++ b/connectivity/source/drivers/mork/MConnection.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCONNECTION_HXX + +#include <TConnection.hxx> +#include "MColumnAlias.hxx" + +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> + +// do we want here namespace too? +class MorkParser; + +namespace connectivity +{ + namespace mork + { + class MorkDriver; + class ErrorDescriptor; + + typedef connectivity::OMetaConnection OConnection_BASE; // implements basics and text encoding + + class OConnection final : public OConnection_BASE + { + // Data attributes + + rtl::Reference<MorkDriver> m_xDriver; // Pointer to the owning + // driver object + OColumnAlias m_aColumnAlias; + // Mork Parser (abook) + std::unique_ptr<MorkParser> m_pBook; + // Mork Parser (history) + std::unique_ptr<MorkParser> m_pHistory; + // Store Catalog + css::uno::Reference< css::sdbcx::XTablesSupplier> m_xCatalog; + + public: + /// @throws css::sdbc::SQLException + void construct( const OUString& url); + explicit OConnection(MorkDriver* const driver); + virtual ~OConnection() override; + + const rtl::Reference<MorkDriver>& getDriver() const {return m_xDriver;}; + MorkParser* getMorkParser(const OString& t) {return t == "CollectedAddressBook" ? m_pHistory.get() : m_pBook.get();}; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings() override; + + const OColumnAlias & getColumnAlias() const { return m_aColumnAlias; } + + static bool getForceLoadTables() {return true;} + + // Added to enable me to use SQLInterpreter which requires an + // XNameAccess i/f to access tables. + css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog(); + + void throwSQLException( const ErrorDescriptor& _rError, const css::uno::Reference< css::uno::XInterface >& _rxContext ); + void throwSQLException( const char* pErrorResourceId, const css::uno::Reference< css::uno::XInterface >& _rxContext ); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MDatabaseMetaData.cxx b/connectivity/source/drivers/mork/MDatabaseMetaData.cxx new file mode 100644 index 000000000..7858230b0 --- /dev/null +++ b/connectivity/source/drivers/mork/MDatabaseMetaData.cxx @@ -0,0 +1,957 @@ +/* -*- 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/. + */ + +#include "MConnection.hxx" +#include "MDatabaseMetaData.hxx" + +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <sal/log.hxx> +#include <vector> + +#include "MDatabaseMetaDataHelper.hxx" + +using namespace connectivity::mork; +using namespace connectivity; + +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; + + +namespace connectivity::mork +{ + static sal_Int32 const s_nCOLUMN_SIZE = 256; + static sal_Int32 const s_nDECIMAL_DIGITS = 0; + static sal_Int32 const s_nNULLABLE = 1; + static sal_Int32 const s_nCHAR_OCTET_LENGTH = 65535; +} + +ODatabaseMetaData::ODatabaseMetaData(OConnection* _pCon) + : ::connectivity::ODatabaseMetaDataBase(_pCon,_pCon->getConnectionInfo()) + ,m_pConnection(_pCon) + ,m_pMetaDataHelper(new MDatabaseMetaDataHelper) +{ + OSL_ENSURE(m_pConnection,"ODatabaseMetaData::ODatabaseMetaData: No connection set!"); +} + +ODatabaseMetaData::~ODatabaseMetaData() +{ +} + + +ODatabaseMetaDataResultSet::ORows ODatabaseMetaData::getColumnRows( + const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + SAL_INFO("connectivity.mork", "=> ODatabaseMetaData::getColumnRows()" ); + SAL_INFO("connectivity.mork", "tableNamePattern: " << tableNamePattern); + SAL_INFO("connectivity.mork", "columnNamePattern: " << columnNamePattern); + + ODatabaseMetaDataResultSet::ORows aRows; + ODatabaseMetaDataResultSet::ORow aRow(19); + + ::osl::MutexGuard aGuard( m_aMutex ); + std::vector< OUString > tables; + connectivity::mork::MDatabaseMetaDataHelper::getTableStrings(m_pConnection, tables); + + // **************************************************** + // Some entries in a row never change, so set them now + // **************************************************** + + // Catalog + aRow[1] = new ORowSetValueDecorator(OUString()); + // Schema + aRow[2] = new ORowSetValueDecorator(OUString()); + // DATA_TYPE + aRow[5] = new ORowSetValueDecorator(static_cast<sal_Int16>(DataType::VARCHAR)); + // TYPE_NAME, not used + aRow[6] = new ORowSetValueDecorator(OUString("VARCHAR")); + // COLUMN_SIZE + aRow[7] = new ORowSetValueDecorator(s_nCOLUMN_SIZE); + // BUFFER_LENGTH, not used + aRow[8] = ODatabaseMetaDataResultSet::getEmptyValue(); + // DECIMAL_DIGITS. + aRow[9] = new ORowSetValueDecorator(s_nDECIMAL_DIGITS); + // NUM_PREC_RADIX + aRow[10] = new ORowSetValueDecorator(sal_Int32(10)); + // NULLABLE + aRow[11] = new ORowSetValueDecorator(s_nNULLABLE); + // REMARKS + aRow[12] = ODatabaseMetaDataResultSet::getEmptyValue(); + // COULUMN_DEF, not used + aRow[13] = ODatabaseMetaDataResultSet::getEmptyValue(); + // SQL_DATA_TYPE, not used + aRow[14] = ODatabaseMetaDataResultSet::getEmptyValue(); + // SQL_DATETIME_SUB, not used + aRow[15] = ODatabaseMetaDataResultSet::getEmptyValue(); + // CHAR_OCTET_LENGTH, refer to [5] + aRow[16] = new ORowSetValueDecorator(s_nCHAR_OCTET_LENGTH); + // IS_NULLABLE + aRow[18] = new ORowSetValueDecorator(OUString("YES")); + + // Iterate over all tables + for(const OUString & table : tables) { + if(match(tableNamePattern, table,'\0')) { + // TABLE_NAME + aRow[3] = new ORowSetValueDecorator( table ); + + const OColumnAlias& colNames = m_pConnection->getColumnAlias(); + + SAL_INFO("connectivity.mork", "\tTableName = : " << table); + // Iterate over all columns in the table. + for (const auto& [rName, rAlias] : colNames) + { + if ( match( columnNamePattern, rName, '\0' ) ) + { + SAL_INFO("connectivity.mork", "\t\tColumnNam : " << rName); + + // COLUMN_NAME + aRow[4] = new ORowSetValueDecorator( rName ); + // ORDINAL_POSITION + aRow[17] = new ORowSetValueDecorator( static_cast< sal_Int32 >( rAlias.columnPosition ) + 1 ); + aRows.push_back(aRow); + } + } + } + } + return aRows; +} + +OUString ODatabaseMetaData::impl_getCatalogSeparator_throw( ) +{ + return OUString(); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return 65535; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength( ) +{ + return 254; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength( ) +{ + return 20; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 ODatabaseMetaData::impl_getMaxStatements_throw( ) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 ODatabaseMetaData::impl_getMaxTablesInSelect_throw( ) +{ + // We only support a single table + return 1; +} + + +sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( ) +{ + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( ) +{ + return 0; // 0 means no limit +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( ) +{ + return false; +} + +OUString SAL_CALL ODatabaseMetaData::getCatalogTerm( ) +{ + return OUString(); +} + +OUString ODatabaseMetaData::impl_getIdentifierQuoteString_throw( ) +{ + // normally this is " + return "\""; +} + +OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + return true; +} + +bool ODatabaseMetaData::impl_isCatalogAtStart_throw( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + //We support create table + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 /*level*/ ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + return true; // should be supported at least +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + return false; +} + +bool ODatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins( ) +{ + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength( ) +{ + return 0;// 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable( ) +{ + // We allow you to select from any table. + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( ) +{ + //we support insert/update/delete now + //But we have to set this to return sal_True otherwise the UI will add create "table/edit table" + //entry to the popup menu. We should avoid them. + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing( ) +{ + // Support added for this. + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert( sal_Int32 /*fromType*/, sal_Int32 /*toType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + return true; +} + +bool ODatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( ) +{ + // Any case may be used + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + return false; +} + +OUString SAL_CALL ODatabaseMetaData::getURL( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return m_pConnection->getURL(); +} + +OUString SAL_CALL ODatabaseMetaData::getUserName( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getDriverName( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getDriverVersion() +{ + OUString aValue = OUString::number(1); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( ) +{ + OUString aValue = OUString::number(0); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getSchemaTerm( ) +{ + return OUString(); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation( ) +{ + return TransactionIsolation::NONE; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( ) +{ + return 0; +} + +OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getStringFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( ) +{ + return OUString(); +} + +OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( ) +{ + return OUString(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return false; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( ) +{ + return 0; // 0 means no limit +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( ) +{ + return 0; // 0 means no limit +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( sal_Int32 /*setType*/, sal_Int32 /*concurrency*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 /*setType*/ ) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates( ) +{ + return false; +} + +// here follow all methods which return a resultset +// the first methods is an example implementation how to use this resultset +// of course you could implement it on your and you should do this because +// the general way is more memory expensive + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( ) +{ + // there exists no possibility to get table types so we have to check + static const OUStringLiteral sTableTypes[] = + { + "TABLE", + "VIEW" + // Currently we only support a 'TABLE' and 'VIEW' nothing more complex + + // OUString("SYSTEM TABLE"), + // OUString("GLOBAL TEMPORARY"), + // OUString("LOCAL TEMPORARY"), + // OUString("ALIAS"), + // OUString("SYNONYM") + }; + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes); + Reference< XResultSet > xRef = pResult; + + // here we fill the rows which should be visible when ask for data from the resultset returned here + ODatabaseMetaDataResultSet::ORows aRows; + for(const auto & sTableType : sTableTypes) + { + ODatabaseMetaDataResultSet::ORow aRow; + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(OUString(sTableType))); + // bound row + aRows.push_back(aRow); + } + // here we set the rows at the resultset + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > ODatabaseMetaData::impl_getTypeInfo_throw( ) +{ + // this returns an empty resultset where the column-names are already set + // in special the metadata of the resultset already returns the right columns + ODatabaseMetaDataResultSet* pResultSet = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo); + Reference< XResultSet > xResultSet = pResultSet; + static ODatabaseMetaDataResultSet::ORows aRows = [&]() + { + ODatabaseMetaDataResultSet::ORows tmp; + ODatabaseMetaDataResultSet::ORow aRow; + aRow.reserve(19); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(OUString("VARCHAR"))); + aRow.push_back(new ORowSetValueDecorator(DataType::VARCHAR)); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(s_nCHAR_OCTET_LENGTH))); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getQuoteValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + // aRow.push_back(new ORowSetValueDecorator((sal_Int32)ColumnValue::NULLABLE)); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR))); + aRow.push_back(ODatabaseMetaDataResultSet::get1Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::get0Value()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRow.push_back(new ORowSetValueDecorator(sal_Int32(10))); + + tmp.push_back(aRow); + return tmp; + }(); + pResultSet->setRows(aRows); + return xResultSet; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + // this returns an empty resultset where the column-names are already set + // in special the metadata of the resultset already returns the right columns + ODatabaseMetaDataResultSet* pResultSet = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eColumns); + Reference< XResultSet > xResultSet = pResultSet; + pResultSet->setRows( getColumnRows( tableNamePattern, columnNamePattern )); + return xResultSet; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, + const OUString& tableNamePattern, const Sequence< OUString >& /*types*/ ) +{ + SAL_INFO("connectivity.mork", "=> ODatabaseMetaData::getTables()" ); + // this returns an empty resultset where the column-names are already set + // in special the metadata of the resultset already returns the right columns + ODatabaseMetaDataResultSet* pResultSet = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables); + Reference< XResultSet > xResultSet = pResultSet; + + // ODatabaseMetaDataResultSet::ORows aRows; + // aRows = m_pDbMetaDataHelper->getTables( m_pConnection, tableNamePattern ); + // pResultSet->setRows( aRows ); + ODatabaseMetaDataResultSet::ORows _rRows; + connectivity::mork::MDatabaseMetaDataHelper::getTables( m_pConnection, tableNamePattern, _rRows ); + pResultSet->setRows( _rRows ); + + return xResultSet; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern ) +{ + SAL_INFO("connectivity.mork", "=> ODatabaseMetaData::getTablePrivileges()" ); + ::connectivity::ODatabaseMetaDataResultSet* pResult = new ::connectivity::ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTablePrivileges); + Reference< XResultSet > xRef = pResult; + + std::vector< OUString > tables; + connectivity::mork::MDatabaseMetaDataHelper::getTableStrings( m_pConnection, tables); + + ::connectivity::ODatabaseMetaDataResultSet::ORows aRows; + ::connectivity::ODatabaseMetaDataResultSet::ORow aRow(8); + aRows.reserve(8); + aRow[0] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[1] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[3] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[4] = ::connectivity::ODatabaseMetaDataResultSet::getEmptyValue(); + aRow[5] = new ::connectivity::ORowSetValueDecorator(getUserName()); + aRow[7] = new ::connectivity::ORowSetValueDecorator(OUString("NO")); + + + // Iterate over all tables + for(const OUString & table : tables) { + if(match(tableNamePattern, table,'\0')) + { + // TABLE_NAME + aRow[2] = new ORowSetValueDecorator( table ); + + SAL_INFO("connectivity.mork", "\tTableName = : " << table); + + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getSelectValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getInsertValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getDeleteValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getUpdateValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getCreateValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getReadValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getAlterValue(); + aRows.push_back(aRow); + aRow[6] = ::connectivity::ODatabaseMetaDataResultSet::getDropValue(); + aRows.push_back(aRow); + } + } + pResult->setRows(aRows); + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ ) +{ + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MDatabaseMetaData.hxx b/connectivity/source/drivers/mork/MDatabaseMetaData.hxx new file mode 100644 index 000000000..8677fc7aa --- /dev/null +++ b/connectivity/source/drivers/mork/MDatabaseMetaData.hxx @@ -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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MDATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MDATABASEMETADATA_HXX + +#include <memory> +#include <TDatabaseMetaDataBase.hxx> +#include "MConnection.hxx" + +namespace connectivity +{ + namespace mork + { + class MDatabaseMetaDataHelper; + + //************ Class: ODatabaseMetaData + + + class ODatabaseMetaData : public ODatabaseMetaDataBase + { + OConnection* m_pConnection; + std::unique_ptr<MDatabaseMetaDataHelper> + m_pMetaDataHelper; + + /// @throws css::sdbc::SQLException + ODatabaseMetaDataResultSet::ORows getColumnRows( const OUString& tableNamePattern, const OUString& columnNamePattern ); + + protected: + virtual ~ODatabaseMetaData() override; + + public: + explicit ODatabaseMetaData(OConnection* _pCon); + + private: + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + // cached database information + virtual OUString impl_getIdentifierQuoteString_throw( ) override; + virtual bool impl_isCatalogAtStart_throw( ) override; + virtual OUString impl_getCatalogSeparator_throw( ) override; + virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override; + virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ; + virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override; + virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ; + virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override ; + virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override; + virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override; + virtual sal_Int32 impl_getMaxStatements_throw( ) override; + virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override; + virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override; + + // as I mentioned before this interface is really BIG + // XDatabaseMetaData + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MDATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MDatabaseMetaDataHelper.cxx b/connectivity/source/drivers/mork/MDatabaseMetaDataHelper.cxx new file mode 100644 index 000000000..ca699bafa --- /dev/null +++ b/connectivity/source/drivers/mork/MDatabaseMetaDataHelper.cxx @@ -0,0 +1,123 @@ +/* -*- 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/. + */ + +#include "MConnection.hxx" +#include "MDatabaseMetaDataHelper.hxx" + +// do we need it? +static ::osl::Mutex m_aMetaMutex; + +#include <sal/log.hxx> + +#include "MorkParser.hxx" + +using namespace connectivity; +using namespace connectivity::mork; + + +MDatabaseMetaDataHelper::MDatabaseMetaDataHelper() +{ + SAL_INFO("connectivity.mork", "=> MDatabaseMetaDataHelper::MDatabaseMetaDataHelper()" ); +} + + +MDatabaseMetaDataHelper::~MDatabaseMetaDataHelper() +{ +} + +void MDatabaseMetaDataHelper::getTableStrings( OConnection* _pCon, + std::vector< OUString >& _rStrings) +{ + SAL_INFO("connectivity.mork", "=> MDatabaseMetaDataHelper::getTableStrings()"); + + /* add default tables */ + _rStrings.push_back("AddressBook"); + _rStrings.push_back("CollectedAddressBook"); + + /* retrieve list table names (not from collected ab) */ + std::set<std::string> lists; + MorkParser* pMork = _pCon->getMorkParser("AddressBook"); + pMork->retrieveLists(lists); + for (auto const& elem : lists) + { + OUString groupTableName = OStringToOUString(elem.c_str(), RTL_TEXTENCODING_UTF8); + SAL_INFO("connectivity.mork", "add Table " << groupTableName); + + _rStrings.push_back(groupTableName); + // remember the list in the mork parser, we'll use it later + pMork->lists_.push_back(groupTableName); + } + + std::set<std::string> lists_history; + pMork = _pCon->getMorkParser("CollectedAddressBook"); + pMork->retrieveLists(lists_history); + for (auto const& elem : lists_history) + { + OUString groupTableName = OStringToOUString(elem.c_str(), RTL_TEXTENCODING_UTF8); + SAL_INFO("connectivity.mork", "add Table " << groupTableName); + + _rStrings.push_back(groupTableName); + // remember the list in the mork parser, we'll use it later + pMork->lists_.push_back(groupTableName); + } +} + +void MDatabaseMetaDataHelper::getTables( OConnection* _pCon, + const OUString& tableNamePattern, + ODatabaseMetaDataResultSet::ORows& _rRows) +{ + + SAL_INFO("connectivity.mork", "=> MDatabaseMetaDataHelper::getTables()"); + + static ODatabaseMetaDataResultSet::ORows aRows; + + SAL_INFO("connectivity.mork", "=> MDatabaseMetaDataHelper::getTables()" ); + SAL_INFO("connectivity.mork", "tableNamePattern : " << tableNamePattern); + ::osl::MutexGuard aGuard( m_aMetaMutex ); + + ODatabaseMetaDataResultSet::ORows().swap(aRows); // this makes real clear where memory is freed as well + aRows.clear(); + + std::vector< OUString > tables; + + getTableStrings( _pCon, tables ); + + for (OUString& aTableName : tables) { + ODatabaseMetaDataResultSet::ORow aRow { nullptr, nullptr, nullptr }; + + SAL_INFO("connectivity.mork", "TableName: " << aTableName ); + + + // return tables to caller + if (match( tableNamePattern, aTableName, '\0' )) + { + if ( aTableName.isEmpty() ) { + aTableName = "AddressBook"; + } + + SAL_INFO("connectivity.mork", "TableName: " << aTableName); + + aRow.push_back( new ORowSetValueDecorator( aTableName ) ); // Table/View name + if ((aTableName == "AddressBook") || (aTableName == "CollectedAddressBook")) + { + aRow.push_back( new ORowSetValueDecorator( OUString("TABLE") ) ); // Table type + } + else + { + aRow.push_back( new ORowSetValueDecorator( OUString("VIEW") ) ); // View type + } + aRow.push_back( ODatabaseMetaDataResultSet::getEmptyValue() ); // Remarks + aRows.push_back(aRow); + } + } + + _rRows = aRows; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MDatabaseMetaDataHelper.hxx b/connectivity/source/drivers/mork/MDatabaseMetaDataHelper.hxx new file mode 100644 index 000000000..0ae96dac9 --- /dev/null +++ b/connectivity/source/drivers/mork/MDatabaseMetaDataHelper.hxx @@ -0,0 +1,39 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MDATABASEMETADATAHELPER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MDATABASEMETADATAHELPER_HXX + +#include <FDatabaseMetaDataResultSet.hxx> +#include "MConnection.hxx" + +namespace connectivity +{ + namespace mork + { + class MDatabaseMetaDataHelper + { + public: + MDatabaseMetaDataHelper(); + ~MDatabaseMetaDataHelper(); + + + static void getTableStrings( OConnection* _pCon, + std::vector< OUString >& _rStrings); + + static void getTables( OConnection* _pCon, + const OUString& tableNamePattern, + ODatabaseMetaDataResultSet::ORows& _rRows); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MDATABASEMETADATAHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MDriver.cxx b/connectivity/source/drivers/mork/MDriver.cxx new file mode 100644 index 000000000..0351b6c3e --- /dev/null +++ b/connectivity/source/drivers/mork/MDriver.cxx @@ -0,0 +1,133 @@ +/* -*- 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/. + */ + +#include "MDriver.hxx" +#include "MConnection.hxx" + +#include <com/sun/star/mozilla/XMozillaBootstrap.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <sal/log.hxx> + +using namespace connectivity::mork; + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_sdbc_MorkDriver_get_implementation( + css::uno::XComponentContext* context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new MorkDriver(context)); +} + +MorkDriver::MorkDriver(const css::uno::Reference< css::uno::XComponentContext >& context): + context_(context), + m_xFactory(context_->getServiceManager(), css::uno::UNO_QUERY) +{ + SAL_INFO("connectivity.mork", "=> MorkDriver::MorkDriver()" ); +} + +OUString SAL_CALL MorkDriver::getImplementationName() +{ + return MORK_DRIVER_IMPL_NAME; +} + +sal_Bool SAL_CALL MorkDriver::supportsService(const OUString& serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +css::uno::Sequence< OUString > MorkDriver::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.Driver" }; +} + +css::uno::Reference< css::sdbc::XConnection > MorkDriver::connect( + OUString const & url, + css::uno::Sequence< css::beans::PropertyValue > const &) +{ + SAL_INFO("connectivity.mork", "=> MorkDriver::connect()" ); + + // Profile discovery + css::uno::Reference<css::uno::XInterface> xInstance = context_->getServiceManager()->createInstanceWithContext("com.sun.star.mozilla.MozillaBootstrap", context_); + OSL_ENSURE( xInstance.is(), "failed to create instance" ); + + css::uno::Reference<css::mozilla::XMozillaBootstrap> xMozillaBootstrap(xInstance, css::uno::UNO_QUERY); + OSL_ENSURE( xMozillaBootstrap.is(), "failed to create instance" ); + + if (xMozillaBootstrap.is()) + { + OUString defaultProfile = xMozillaBootstrap->getDefaultProfile(css::mozilla::MozillaProductType_Thunderbird); + + if (!defaultProfile.isEmpty()) + { + m_sProfilePath = xMozillaBootstrap->getProfilePath(css::mozilla::MozillaProductType_Thunderbird, defaultProfile); + SAL_INFO("connectivity.mork", "Using Thunderbird profile " << m_sProfilePath); + } + } + + css::uno::Reference< css::sdbc::XConnection > xCon; + OConnection* pCon = new OConnection(this); + xCon = pCon; // important here because otherwise the connection could be deleted inside (refcount goes -> 0) + pCon->construct(url); + return xCon; +} + +sal_Bool MorkDriver::acceptsURL(OUString const & url) +{ + SAL_INFO("connectivity.mork", "=> MorkDriver::acceptsURL()" ); + // Skip 'sdbc:mozab: part of URL + + sal_Int32 nLen = url.indexOf(':'); + nLen = url.indexOf(':',nLen+1); + OUString aAddrbookURI(url.copy(nLen+1)); + // Get Scheme + nLen = aAddrbookURI.indexOf(':'); + OUString aAddrbookScheme; + if ( nLen == -1 ) + { + // There isn't any subschema: - but could be just subschema + if ( !aAddrbookURI.isEmpty() ) + { + aAddrbookScheme= aAddrbookURI; + } + else if( url == "sdbc:address:" ) + { + return false; + } + else + { + return false; + } + } + else + { + aAddrbookScheme = aAddrbookURI.copy(0, nLen); + } + + return aAddrbookScheme == "thunderbird" || aAddrbookScheme == "mozilla"; +} + +css::uno::Sequence< css::sdbc::DriverPropertyInfo > MorkDriver::getPropertyInfo( + OUString const &, + css::uno::Sequence< css::beans::PropertyValue > const &) +{ + //... TODO + return css::uno::Sequence< css::sdbc::DriverPropertyInfo >(); +} + +sal_Int32 MorkDriver::getMajorVersion() { + //... TODO + return 0; +} + +sal_Int32 MorkDriver::getMinorVersion() { + //... TODO + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MDriver.hxx b/connectivity/source/drivers/mork/MDriver.hxx new file mode 100644 index 000000000..6f6946af6 --- /dev/null +++ b/connectivity/source/drivers/mork/MDriver.hxx @@ -0,0 +1,79 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MDRIVER_HXX + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/DriverPropertyInfo.hpp> + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <cppuhelper/implbase.hxx> + +#define MORK_DRIVER_IMPL_NAME "com.sun.star.comp.sdbc.MorkDriver" + +namespace com::sun::star { + namespace uno { + class XComponentContext; + class XInterface; + } +} + +namespace connectivity::mork { +class ProfileAccess; + +class MorkDriver: + public cppu::WeakImplHelper< css::lang::XServiceInfo, css::sdbc::XDriver > +{ +public: + explicit MorkDriver(const css::uno::Reference< css::uno::XComponentContext >& context); + + const css::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& getFactory() const {return m_xFactory;} + const OUString& getProfilePath() const {return m_sProfilePath;} +private: + + MorkDriver(const MorkDriver&) = delete; + MorkDriver& operator=(const MorkDriver&) = delete; + + virtual ~MorkDriver() override {} + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( + OUString const & url, + css::uno::Sequence< css::beans::PropertyValue > const & info) override; + + virtual sal_Bool SAL_CALL acceptsURL( + OUString const & url) override; + + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL + getPropertyInfo( + OUString const & url, + css::uno::Sequence< css::beans::PropertyValue > const & info) override; + + virtual sal_Int32 SAL_CALL getMajorVersion() override; + + virtual sal_Int32 SAL_CALL getMinorVersion() override; + + css::uno::Reference< css::uno::XComponentContext > context_; + css::uno::Reference< css::lang::XMultiServiceFactory > m_xFactory; + OUString m_sProfilePath; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MErrorResource.hxx b/connectivity/source/drivers/mork/MErrorResource.hxx new file mode 100644 index 000000000..0691b1813 --- /dev/null +++ b/connectivity/source/drivers/mork/MErrorResource.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MERRORRESOURCE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MERRORRESOURCE_HXX + +namespace connectivity +{ + namespace mork + { + class ErrorDescriptor + { + private: + const char* m_pErrorResourceId; + + public: + ErrorDescriptor() + :m_pErrorResourceId(nullptr) + { + } + + void setResId(const char* pErrorResourceId) + { + m_pErrorResourceId = pErrorResourceId; + } + void reset() + { + m_pErrorResourceId = nullptr; + } + + const char* getResId() const { return m_pErrorResourceId; } + + bool is() const { return m_pErrorResourceId != nullptr; } + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MERRORRESOURCE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MPreparedStatement.cxx b/connectivity/source/drivers/mork/MPreparedStatement.cxx new file mode 100644 index 000000000..f2cd8fdc7 --- /dev/null +++ b/connectivity/source/drivers/mork/MPreparedStatement.cxx @@ -0,0 +1,486 @@ +/* -*- 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/. + */ + +#include <connectivity/sdbcx/VColumn.hxx> +#include "MPreparedStatement.hxx" +#include "MResultSetMetaData.hxx" +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <sal/log.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::mork; +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::container; +using namespace com::sun::star::util; + +IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.mork.PreparedStatement","com.sun.star.sdbc.PreparedStatement"); + + +OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const OUString& sql) + :OCommonStatement(_pConnection) + ,m_sSqlStatement(sql) + ,m_pResultSet() +{ +} + +OPreparedStatement::~OPreparedStatement() +{ +} + +void OPreparedStatement::lateInit() +{ + if ( eSelect != parseSql( m_sSqlStatement ) ) + throw SQLException(); +} + +void SAL_CALL OPreparedStatement::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + OCommonStatement::disposing(); + + m_xMetaData.clear(); + if(m_aParameterRow.is()) + { + m_aParameterRow->clear(); + m_aParameterRow = nullptr; + } + m_xParamColumns = nullptr; +} + +OCommonStatement::StatementType OPreparedStatement::parseSql( const OUString& sql , bool bAdjusted ) +{ + StatementType eStatementType = OCommonStatement::parseSql( sql, bAdjusted ); + if ( eStatementType != eSelect ) + return eStatementType; + + m_xParamColumns = new OSQLColumns(); + + // describe all parameters need for the resultset + describeParameter(); + + Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY); + OResultSet::setBoundedColumns( m_aRow, m_xParamColumns, xNames, false, m_xDBMetaData, m_aColMapping ); + + return eStatementType; +} + +void OPreparedStatement::initializeResultSet( OResultSet* _pResult ) +{ + OCommonStatement::initializeResultSet( _pResult ); + _pResult->setParameterRow( m_aParameterRow ); +} + + +void OPreparedStatement::clearCachedResultSet() +{ + OCommonStatement::clearCachedResultSet(); + m_pResultSet.clear(); + m_xMetaData.clear(); +} + +void OPreparedStatement::cacheResultSet( const ::rtl::Reference< OResultSet >& _pResult ) +{ + OCommonStatement::cacheResultSet( _pResult ); + OSL_PRECOND( m_pResultSet == nullptr, "OPreparedStatement::parseSql: you should call clearCachedResultSet before!" ); + m_pResultSet = _pResult; +} + + +void SAL_CALL OPreparedStatement::acquire() throw() +{ + OCommonStatement::acquire(); +} + +void SAL_CALL OPreparedStatement::release() throw() +{ + OCommonStatement::release(); +} + +Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType ) +{ + Any aRet = OCommonStatement::queryInterface(rType); + if(!aRet.hasValue()) + aRet = OPreparedStatement_BASE::queryInterface(rType); + return aRet; +} + +css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( ) +{ + return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OCommonStatement::getTypes()); +} + + +Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + bool bReadOnly = true; + if ( m_pResultSet.is() ) + bReadOnly = m_pResultSet->determineReadOnly(); + // if we do not have a result set, then we have not been executed, yet. In this case, assuming readonly=true is + // okay, /me thinks. + + if ( !m_xMetaData.is() ) + m_xMetaData = new OResultSetMetaData( m_pSQLIterator->getSelectColumns(), m_pSQLIterator->getTables().begin()->first ,m_pTable,bReadOnly ); + + return m_xMetaData; +} + + +sal_Bool SAL_CALL OPreparedStatement::execute( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + Reference< XResultSet> xResult = executeQuery(); + return xResult.is(); +} + + +sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XStatement::executeUpdate", *this ); + return 0; +} + + +void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + setParameter( parameterIndex, x ); +} + + +Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + return Reference< XConnection >(m_pConnection.get()); +} + + +Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + // our statement has already been parsed in lateInit, no need to do all this (potentially expensive) + // stuff again. Just execute. + return impl_executeCurrentQuery(); +} + + +void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 /*parameterIndex*/, sal_Bool /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setBoolean", *this ); +} + +void SAL_CALL OPreparedStatement::setByte( sal_Int32 /*parameterIndex*/, sal_Int8 /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setByte", *this ); +} + + +void SAL_CALL OPreparedStatement::setDate( sal_Int32 /*parameterIndex*/, const Date& /*aData*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setDate", *this ); +} + + +void SAL_CALL OPreparedStatement::setTime( sal_Int32 /*parameterIndex*/, const css::util::Time& /*aVal*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setTime", *this ); +} + + +void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 /*parameterIndex*/, const DateTime& /*aVal*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setTimestamp", *this ); +} + + +void SAL_CALL OPreparedStatement::setDouble( sal_Int32 /*parameterIndex*/, double /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setDouble", *this ); +} + + +void SAL_CALL OPreparedStatement::setFloat( sal_Int32 /*parameterIndex*/, float /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setFloat", *this ); +} + + +void SAL_CALL OPreparedStatement::setInt( sal_Int32 /*parameterIndex*/, sal_Int32 /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setInt", *this ); +} + + +void SAL_CALL OPreparedStatement::setLong( sal_Int32 /*parameterIndex*/, sal_Int64 /*aVal*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setLong", *this ); +} + + +void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + checkAndResizeParameters(parameterIndex); + + (*m_aParameterRow)[parameterIndex].setNull(); +} + + +void SAL_CALL OPreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setClob", *this ); +} + + +void SAL_CALL OPreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setBlob", *this ); +} + + +void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setArray", *this ); +} + + +void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setRef", *this ); +} + + +void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 /*parameterIndex*/, const Any& /*x*/, sal_Int32 /*sqlType*/, sal_Int32 /*scale*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setObjectWithInfo", *this ); +} + + +void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ ) +{ + setNull(parameterIndex,sqlType); +} + + +void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) +{ + ::dbtools::implSetObject(this,parameterIndex,x); +} + + +void SAL_CALL OPreparedStatement::setShort( sal_Int32 /*parameterIndex*/, sal_Int16 /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setShort", *this ); +} + + +void SAL_CALL OPreparedStatement::setBytes( sal_Int32 /*parameterIndex*/, const Sequence< sal_Int8 >& /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setBytes", *this ); +} + + +void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 /*parameterIndex*/, const Reference< css::io::XInputStream >& /*x*/, sal_Int32 /*length*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setCharacterStream", *this ); +} + + +void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 /*parameterIndex*/, const Reference< css::io::XInputStream >& /*x*/, sal_Int32 /*length*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setBinaryStream", *this ); +} + + +void SAL_CALL OPreparedStatement::clearParameters( ) +{ +} + +void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + switch(nHandle) + { + case PROPERTY_ID_RESULTSETCONCURRENCY: + break; + case PROPERTY_ID_RESULTSETTYPE: + break; + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_USEBOOKMARKS: + break; + default: + OCommonStatement::setFastPropertyValue_NoBroadcast(nHandle,rValue); + } +} + + +void OPreparedStatement::checkAndResizeParameters(sal_Int32 parameterIndex) +{ + ::connectivity::checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + if ( !m_aParameterRow.is() ) { + m_aParameterRow = new OValueVector(); + m_aParameterRow->push_back(sal_Int32(0)); + } + + if (static_cast<sal_Int32>(m_aParameterRow->size()) <= parameterIndex) + m_aParameterRow->resize(parameterIndex+1); +} + +void OPreparedStatement::setParameter(sal_Int32 parameterIndex, const +ORowSetValue& x) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkAndResizeParameters(parameterIndex); + + SAL_INFO( + "connectivity.mork", + "setParameter(" << parameterIndex << ", '" << x.getString() << "')"); + (*m_aParameterRow)[parameterIndex] = x; +} + + +void OPreparedStatement::AddParameter(OSQLParseNode const * pParameter, const Reference<XPropertySet>& _xCol) +{ + OSL_ENSURE(SQL_ISRULE(pParameter,parameter),"OResultSet::AddParameter: Argument is not a Parameter"); + OSL_ENSURE(pParameter->count() > 0,"OResultSet: error in parse tree"); + + OUString sParameterName; + + // set up Parameter-Column: + sal_Int32 eType = DataType::VARCHAR; + sal_uInt32 nPrecision = 255; + sal_Int32 nScale = 0; + sal_Int32 nNullable = ColumnValue::NULLABLE; + + if (_xCol.is()) + { + // Type, Precision, Scale ... utilize the selected Columns, + // then this Column will get the value assigned or with this + // Column will the value be compared. + eType = getINT32(_xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))); + nPrecision = getINT32(_xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))); + nScale = getINT32(_xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))); + nNullable = getINT32(_xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))); + _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sParameterName; + } + + Reference<XPropertySet> xParaColumn = new connectivity::sdbcx::OColumn(sParameterName + ,OUString() + ,OUString() + ,OUString() + ,nNullable + ,nPrecision + ,nScale + ,eType + ,false + ,false + ,false + ,m_pSQLIterator->isCaseSensitive() + ,OUString() + ,OUString() + ,OUString()); + m_xParamColumns->push_back(xParaColumn); +} + +void OPreparedStatement::describeColumn(OSQLParseNode const * _pParameter, + OSQLParseNode const * _pNode, + const OSQLTable& _xTable) +{ + Reference<XPropertySet> xProp; + if(SQL_ISRULE(_pNode,column_ref)) + { + OUString sColumnName,sTableRange; + m_pSQLIterator->getColumnRange(_pNode,sColumnName,sTableRange); + if(!sColumnName.isEmpty()) + { + Reference<XNameAccess> xNameAccess = _xTable->getColumns(); + if(xNameAccess->hasByName(sColumnName)) + xNameAccess->getByName(sColumnName) >>= xProp; + AddParameter(_pParameter,xProp); + } + } + // else + // AddParameter(_pParameter,xProp); +} + +void OPreparedStatement::describeParameter() +{ + std::vector< OSQLParseNode*> aParseNodes; + scanParameter(m_pParseTree.get(), aParseNodes); + if(aParseNodes.empty()) + return; + + m_xParamColumns = new OSQLColumns(); + const OSQLTables& rTabs = m_pSQLIterator->getTables(); + if(!rTabs.empty()) + { + OSQLTable xTable = rTabs.begin()->second; + for (auto const& parseNode : aParseNodes) + { + describeColumn(parseNode,parseNode->getParent()->getChild(0),xTable); + } + } +} + + +void OPreparedStatement::scanParameter(OSQLParseNode* pParseNode,std::vector< OSQLParseNode*>& _rParaNodes) +{ + OSL_ENSURE(pParseNode != nullptr,"OResultSet: internal error: invalid ParseNode"); + + // Parameter Name-Row found? + if (SQL_ISRULE(pParseNode,parameter)) + { + OSL_ENSURE(pParseNode->count() >= 1,"OResultSet: Faulty Parse Tree"); + OSL_ENSURE(pParseNode->getChild(0)->getNodeType() == SQLNodeType::Punctuation,"OResultSet: Faulty Parse Tree"); + + _rParaNodes.push_back(pParseNode); + // further search isn't necessary + return; + } + + // Search on in Parse Tree + for (size_t i = 0; i < pParseNode->count(); i++) + scanParameter(pParseNode->getChild(i),_rParaNodes); +} + +css::uno::Reference< css::sdbc::XResultSet > SAL_CALL OPreparedStatement::getResultSet( ) +{ + return nullptr; +} + +sal_Int32 SAL_CALL OPreparedStatement::getUpdateCount( ) +{ + return 0; +} + +sal_Bool SAL_CALL OPreparedStatement::getMoreResults( ) +{ + return false; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MPreparedStatement.hxx b/connectivity/source/drivers/mork/MPreparedStatement.hxx new file mode 100644 index 000000000..c40ffc909 --- /dev/null +++ b/connectivity/source/drivers/mork/MPreparedStatement.hxx @@ -0,0 +1,134 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MPREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MPREPAREDSTATEMENT_HXX + +#include "MResultSet.hxx" +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <cppuhelper/implbase5.hxx> + +namespace connectivity +{ + namespace mork + { + + typedef ::cppu::ImplHelper5< css::sdbc::XPreparedStatement, + css::sdbc::XParameters, + css::sdbc::XResultSetMetaDataSupplier, + css::sdbc::XMultipleResults, + css::lang::XServiceInfo> OPreparedStatement_BASE; + + class OPreparedStatement final : public OCommonStatement, + public OPreparedStatement_BASE + { + // Data attributes + + OUString m_sSqlStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData; + ::rtl::Reference< OResultSet > m_pResultSet; + ::rtl::Reference<connectivity::OSQLColumns> m_xParamColumns; // the parameter columns + OValueRow m_aParameterRow; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, + const css::uno::Any& rValue) override; + virtual ~OPreparedStatement() override; + + virtual void SAL_CALL disposing() override; + + // OCommonStatement overridables + virtual StatementType + parseSql( const OUString& sql , bool bAdjusted = false) override; + virtual void initializeResultSet( OResultSet* _pResult ) override; + virtual void clearCachedResultSet() override; + virtual void cacheResultSet( const ::rtl::Reference< OResultSet >& _pResult ) override; + + + void checkAndResizeParameters(sal_Int32 parameterIndex); + void setParameter(sal_Int32 parameterIndex, const ORowSetValue& x); + + void AddParameter(connectivity::OSQLParseNode const * pParameter, + const css::uno::Reference< css::beans::XPropertySet>& _xCol); + void scanParameter(OSQLParseNode* pParseNode,std::vector< OSQLParseNode*>& _rParaNodes); + void describeColumn(OSQLParseNode const * _pParameter, OSQLParseNode const * _pNode, const OSQLTable& _xTable); + void describeParameter(); + + public: + DECLARE_SERVICE_INFO(); + // A ctor need for returning the object + OPreparedStatement( OConnection* _pConnection,const OUString& sql); + void lateInit(); + + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + virtual sal_Bool SAL_CALL execute( ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + + public: + using OCommonStatement::executeQuery; + using OCommonStatement::executeUpdate; + using OCommonStatement::execute; + private: + using OPropertySetHelper::getFastPropertyValue; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MPREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MQueryHelper.cxx b/connectivity/source/drivers/mork/MQueryHelper.cxx new file mode 100644 index 000000000..aaf8cac6a --- /dev/null +++ b/connectivity/source/drivers/mork/MQueryHelper.cxx @@ -0,0 +1,321 @@ +/* -*- 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 "MColumnAlias.hxx" +#include "MQueryHelper.hxx" +#include "MConnection.hxx" + +#include "MorkParser.hxx" +#include <string> +#include <vector> +#include <algorithm> + +#include <strings.hrc> + +#include <unotools/textsearch.hxx> +#include <sal/log.hxx> + +using namespace connectivity::mork; +using namespace connectivity; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; + + +static +std::vector<bool> entryMatchedByExpression(MQueryHelper* _aQuery, MQueryExpression const * _aExpr, MQueryHelperResultEntry* entry); + +MQueryHelperResultEntry::MQueryHelperResultEntry() +{ +} + +MQueryHelperResultEntry::~MQueryHelperResultEntry() +{ +} + +OUString MQueryHelperResultEntry::getValue( const OString &key ) const +{ + FieldMap::const_iterator iter = m_Fields.find( key ); + if ( iter == m_Fields.end() ) + { + return OUString(); + } + else + { + return iter->second; + } +} + +void MQueryHelperResultEntry::setValue( const OString &key, const OUString & rValue) +{ + m_Fields[ key ] = rValue; +} + +MQueryHelper::MQueryHelper(const OColumnAlias& _ca) + :m_rColumnAlias( _ca ) + ,m_aError() +{ + m_aResults.clear(); +} + +MQueryHelper::~MQueryHelper() +{ + clear_results(); +} + + +void MQueryHelper::setAddressbook(OUString const &ab) +{ + ::osl::MutexGuard aGuard(m_aMutex); + m_aAddressbook = ab; +} + +void MQueryHelper::append(std::unique_ptr<MQueryHelperResultEntry> resEnt) +{ + assert(resEnt); + m_aResults.push_back( std::move(resEnt) ); +} + +void MQueryHelper::clear_results() +{ + m_aResults.clear(); +} + +void MQueryHelper::reset() +{ + clear_results(); + m_aError.reset(); +} + +MQueryHelperResultEntry* +MQueryHelper::getByIndex(sal_uInt32 nRow) +{ + // Row numbers are from 1 to N, need to ensure this, and then + // subtract 1 + if ( nRow < 1 ) { + return nullptr; + } + return m_aResults[nRow -1].get(); +} + +sal_Int32 MQueryHelper::getResultCount() const +{ + sal_Int32 result = static_cast<sal_Int32>(m_aResults.size()); + + return result; +} + +bool MQueryHelper::getRowValue( ORowSetValue& rValue, sal_Int32 nDBRow,const OUString& aDBColumnName, sal_Int32 nType ) +{ + MQueryHelperResultEntry* pResEntry = getByIndex( nDBRow ); + + OSL_ENSURE( pResEntry != nullptr, "xResEntry == NULL"); + if (pResEntry == nullptr ) + { + rValue.setNull(); + return false; + } + switch ( nType ) + { + case DataType::VARCHAR: + rValue = pResEntry->getValue( m_rColumnAlias.getProgrammaticNameOrFallbackToUTF8Alias( aDBColumnName ) ); + break; + + default: + rValue.setNull(); + break; + } + + return true; +} + +sal_Int32 MQueryHelper::executeQuery(OConnection* xConnection, MQueryExpression & expr) +{ + reset(); + + OString oStringTable = OUStringToOString( m_aAddressbook, RTL_TEXTENCODING_UTF8 ); + std::set<int> listRecords; + bool handleListTable = false; + MorkParser* pMork; + + // check if we are retrieving the default table + if (oStringTable == "AddressBook" || oStringTable == "CollectedAddressBook") + { + pMork = xConnection->getMorkParser(oStringTable); + } + else + { + // Let's try to retrieve the list in Collected Addresses book + pMork = xConnection->getMorkParser("CollectedAddressBook"); + if (std::find(pMork->lists_.begin(), pMork->lists_.end(), m_aAddressbook) == pMork->lists_.end()) + { + // so the list is in Address book + // TODO : manage case where an address book has been created + pMork = xConnection->getMorkParser("AddressBook"); + } + handleListTable = true; + // retrieve row ids for that list table + std::string listTable = oStringTable.getStr(); + pMork->getRecordKeysForListTable(listTable, listRecords); + } + + MorkTableMap *Tables = pMork->getTables( 0x80 ); + if (!Tables) + return -1; + + MorkRowMap *Rows = nullptr; + + // Iterate all tables + for (auto & table : Tables->map) + { + if (table.first != 1) break; + Rows = MorkParser::getRows( 0x80, &table.second ); + if ( Rows ) + { + // Iterate all rows + for (auto const& row : Rows->map) + { + // list specific table + // only retrieve rowIds that belong to that list table. + if (handleListTable) + { + int rowId = row.first; + // belongs this row id to the list table? + if (listRecords.end() == listRecords.find(rowId)) + { + // no, skip it + continue; + } + } + + std::unique_ptr<MQueryHelperResultEntry> entry(new MQueryHelperResultEntry()); + for (auto const& cell : row.second) + { + std::string column = pMork->getColumn(cell.first); + std::string value = pMork->getValue(cell.second); + OString key(column.c_str(), static_cast<sal_Int32>(column.size())); + OString valueOString(value.c_str(), static_cast<sal_Int32>(value.size())); + OUString valueOUString = OStringToOUString( valueOString, RTL_TEXTENCODING_UTF8 ); + entry->setValue(key, valueOUString); + } + bool result = true; + for (bool elem : entryMatchedByExpression(this, &expr, entry.get())) + { + result = result && elem; + } + if (result) + { + append(std::move(entry)); + } + } + } + } + return 0; +} + +std::vector<bool> entryMatchedByExpression(MQueryHelper* _aQuery, MQueryExpression const * _aExpr, MQueryHelperResultEntry* entry) +{ + std::vector<bool> resultVector; + for (auto const& expr : _aExpr->getExpressions()) + { + if ( expr->isStringExpr() ) { + MQueryExpressionString* evStr = static_cast<MQueryExpressionString*> (expr); + // Set the 'name' property of the boolString. + OString attrName = _aQuery->getColumnAlias().getProgrammaticNameOrFallbackToUTF8Alias( evStr->getName() ); + SAL_INFO("connectivity.mork", "Name = " << attrName); + bool bRequiresValue = true; + OUString currentValue = entry->getValue(attrName); + if (evStr->getCond() == MQueryOp::Exists || evStr->getCond() == MQueryOp::DoesNotExist) + { + bRequiresValue = false; + } + if (bRequiresValue) + { + SAL_INFO("connectivity.mork", "Value = " << evStr->getValue() ); + const OUString& searchedValue = evStr->getValue(); + if (evStr->getCond() == MQueryOp::Is) { + SAL_INFO("connectivity.mork", "MQueryOp::Is; done"); + resultVector.push_back(currentValue == searchedValue); + } else if (evStr->getCond() == MQueryOp::IsNot) { + SAL_INFO("connectivity.mork", "MQueryOp::IsNot; done"); + resultVector.push_back(currentValue != searchedValue); + } else if (evStr->getCond() == MQueryOp::EndsWith) { + SAL_INFO("connectivity.mork", "MQueryOp::EndsWith; done"); + resultVector.push_back(currentValue.endsWith(searchedValue)); + } else if (evStr->getCond() == MQueryOp::BeginsWith) { + SAL_INFO("connectivity.mork", "MQueryOp::BeginsWith; done"); + resultVector.push_back(currentValue.startsWith(searchedValue)); + } else if (evStr->getCond() == MQueryOp::Contains) { + SAL_INFO("connectivity.mork", "MQueryOp::Contains; done"); + resultVector.push_back(currentValue.indexOf(searchedValue) != -1); + } else if (evStr->getCond() == MQueryOp::DoesNotContain) { + SAL_INFO("connectivity.mork", "MQueryOp::DoesNotContain; done"); + resultVector.push_back(currentValue.indexOf(searchedValue) == -1); + } else if (evStr->getCond() == MQueryOp::RegExp) { + SAL_INFO("connectivity.mork", "MQueryOp::RegExp; done"); + utl::SearchParam param( + searchedValue, utl::SearchParam::SearchType::Regexp); + utl::TextSearch ts(param, LANGUAGE_DONTKNOW); + sal_Int32 start = 0; + sal_Int32 end = currentValue.getLength(); + resultVector.push_back( + ts.SearchForward(currentValue, &start, &end)); + } + } else if (evStr->getCond() == MQueryOp::Exists) { + SAL_INFO("connectivity.mork", "MQueryOp::Exists; done"); + resultVector.push_back(!currentValue.isEmpty()); + } else if (evStr->getCond() == MQueryOp::DoesNotExist) { + SAL_INFO("connectivity.mork", "MQueryOp::DoesNotExist; done"); + resultVector.push_back(currentValue.isEmpty()); + } + } + else if ( expr->isExpr() ) { + SAL_INFO("connectivity.mork", "Appending Subquery Expression"); + MQueryExpression* queryExpression = static_cast<MQueryExpression*> (expr); + // recursive call + std::vector<bool> subquery_result = entryMatchedByExpression(_aQuery, queryExpression, entry); + MQueryExpression::bool_cond condition = queryExpression->getExpressionCondition(); + if (condition == MQueryExpression::OR) { + bool result = false; + for (bool elem : subquery_result) + { + result = result || elem; + } + resultVector.push_back(result); + } else { + assert(condition == MQueryExpression::AND && "only OR or AND should exist"); + bool result = true; + for (bool elem : subquery_result) + { + result = result && elem; + } + resultVector.push_back(result); + } + } + else { + // Should never see this... + SAL_WARN("connectivity.mork", "Unknown Expression Type!"); + _aQuery->getError().setResId(STR_ERROR_GET_ROW); + return resultVector; + } + } + return resultVector; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MQueryHelper.hxx b/connectivity/source/drivers/mork/MQueryHelper.hxx new file mode 100644 index 000000000..67d2b081d --- /dev/null +++ b/connectivity/source/drivers/mork/MQueryHelper.hxx @@ -0,0 +1,184 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MQUERYHELPER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MQUERYHELPER_HXX + +#include <connectivity/FValue.hxx> +#include "MErrorResource.hxx" +#include "MColumnAlias.hxx" + +namespace connectivity +{ + namespace mork + { + class OConnection; + class MQueryHelper; + class ErrorDescriptor; + + namespace MQueryOp { + typedef enum { + Exists = 0, + DoesNotExist = 1, + Contains = 2, + DoesNotContain = 3, + Is = 4, + IsNot = 5, + BeginsWith = 6, + EndsWith = 7, + RegExp = 8 + } cond_type; + } + + class MQueryExpressionBase { + public: + enum class node_type { + StringExpr, + Expr + }; + + protected: + node_type m_eNodeType; + + explicit MQueryExpressionBase( node_type _eNodeType ) : m_eNodeType( _eNodeType ) {} + + public: + virtual ~MQueryExpressionBase() {} + + bool isStringExpr( ) const { return m_eNodeType == node_type::StringExpr; } + bool isExpr( ) const { return m_eNodeType == node_type::Expr; } + }; + + class MQueryExpressionString final : public MQueryExpressionBase { + OUString m_aName; // LHS + MQueryOp::cond_type m_aBooleanCondition; + OUString m_aValue; // RHS + + public: + + MQueryExpressionString( const OUString& lhs, + MQueryOp::cond_type cond, + const OUString& rhs ) + : MQueryExpressionBase( MQueryExpressionBase::node_type::StringExpr ) + , m_aName( lhs ) + , m_aBooleanCondition( cond ) + , m_aValue( rhs ) + { + } + + MQueryExpressionString( const OUString& lhs, + MQueryOp::cond_type cond ) + : MQueryExpressionBase( MQueryExpressionBase::node_type::StringExpr ) + , m_aName( lhs ) + , m_aBooleanCondition( cond ) + , m_aValue( OUString() ) + { + } + + const OUString& getName() const { return m_aName; } + MQueryOp::cond_type getCond() const { return m_aBooleanCondition; } + const OUString& getValue() const { return m_aValue; } + }; + + class MQueryExpression final : public MQueryExpressionBase + { + friend class MQueryHelper; + + public: + typedef std::vector< MQueryExpressionBase* > ExprVector; + + typedef enum { + AND, + OR + } bool_cond; + + // All expressions on a peer level use same condition operator + void setExpressionCondition( bool_cond _cond ) + { m_aExprCondType = _cond; } + + void addExpression(MQueryExpressionBase * expr) + { m_aExprVector.push_back(expr); } + + ExprVector const & getExpressions( ) const + { return m_aExprVector; } + + // All expressions on a peer level use same condition operator + bool_cond getExpressionCondition( ) const + { return m_aExprCondType; } + + MQueryExpression() : MQueryExpressionBase( MQueryExpressionBase::node_type::Expr ), + m_aExprCondType( OR ) + {} + + private: + ExprVector m_aExprVector; + bool_cond m_aExprCondType; + + MQueryExpression(const MQueryExpression&) = delete; + MQueryExpression& operator=(const MQueryExpression&) = delete; + }; + + class MQueryHelperResultEntry + { + private: + typedef std::unordered_map< OString, OUString > FieldMap; + + FieldMap m_Fields; + + public: + MQueryHelperResultEntry(); + ~MQueryHelperResultEntry(); + + OUString getValue( const OString &key ) const; + void setValue( const OString &key, const OUString & rValue); + }; + + class MQueryHelper final + { + private: + + mutable ::osl::Mutex m_aMutex; + std::vector< std::unique_ptr<MQueryHelperResultEntry> > m_aResults; + void append(std::unique_ptr<MQueryHelperResultEntry> resEnt ); + void clear_results(); + OColumnAlias m_rColumnAlias; + ErrorDescriptor m_aError; + OUString m_aAddressbook; + + public: + explicit MQueryHelper(const OColumnAlias& _ca); + ~MQueryHelper(); + + void reset(); + MQueryHelperResultEntry* getByIndex( sal_uInt32 nRow ); + sal_Int32 getResultCount() const; + bool getRowValue( ORowSetValue& rValue, sal_Int32 nDBRow,const OUString& aDBColumnName, sal_Int32 nType ); + sal_Int32 executeQuery(OConnection* xConnection, MQueryExpression & expr); + const OColumnAlias& getColumnAlias() const { return m_rColumnAlias; } + bool hadError() const { return m_aError.is(); } + ErrorDescriptor& getError() { return m_aError; } + + void setAddressbook( OUString const &); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MQUERYHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MResultSet.cxx b/connectivity/source/drivers/mork/MResultSet.cxx new file mode 100644 index 000000000..ab6b11a9d --- /dev/null +++ b/connectivity/source/drivers/mork/MResultSet.cxx @@ -0,0 +1,1710 @@ +/* -*- 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 <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <o3tl/safeint.hxx> +#include <sal/log.hxx> + +#include <vector> +#include <algorithm> +#include "MResultSet.hxx" +#include <sqlbison.hxx> +#include "MResultSetMetaData.hxx" +#include <FDatabaseMetaDataResultSet.hxx> + +#include <strings.hrc> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::mork; +using namespace ::cppu; +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + + +// IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.OResultSet","com.sun.star.sdbc.ResultSet"); +OUString SAL_CALL OResultSet::getImplementationName( ) +{ + return "com.sun.star.sdbcx.mork.ResultSet"; +} + + Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames( ) +{ + return {"com.sun.star.sdbc.ResultSet","com.sun.star.sdbcx.ResultSet"}; +} + +sal_Bool SAL_CALL OResultSet::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +OResultSet::OResultSet(OCommonStatement* pStmt, const std::shared_ptr< connectivity::OSQLParseTreeIterator >& _pSQLIterator ) + : OResultSet_BASE(m_aMutex) + ,OPropertySetHelper(OResultSet_BASE::rBHelper) + ,m_pStatement(pStmt) + ,m_xStatement(*pStmt) + ,m_nRowPos(0) + ,m_bWasNull(false) + ,m_nResultSetType(ResultSetType::SCROLL_INSENSITIVE) + ,m_nFetchDirection(FetchDirection::FORWARD) + ,m_pSQLIterator( _pSQLIterator ) + ,m_pParseTree( _pSQLIterator->getParseTree() ) + ,m_aQueryHelper(pStmt->getOwnConnection()->getColumnAlias()) + ,m_CurrentRowCount(0) + ,m_nParamIndex(0) + ,m_bIsAlwaysFalseQuery(false) + ,m_bIsReadOnly(TRISTATE_INDET) +{ + //m_aQuery.setMaxNrOfReturns(pStmt->getOwnConnection()->getMaxResultRecords()); +} + +OResultSet::~OResultSet() +{ +} + + +void OResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + + m_xStatement.clear(); + m_xMetaData.clear(); + m_pParseTree = nullptr; + m_xColumns = nullptr; + m_pKeySet = nullptr; + m_xTable.clear(); +} + +Any SAL_CALL OResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + if(!aRet.hasValue()) + aRet = OResultSet_BASE::queryInterface(rType); + return aRet; +} + + Sequence< Type > SAL_CALL OResultSet::getTypes( ) +{ + 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(),OResultSet_BASE::getTypes()); +} + +void OResultSet::methodEntry() +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + if ( !m_xTable.is() ) + { + OSL_FAIL( "OResultSet::methodEntry: looks like we're disposed, but how is this possible?" ); + throw DisposedException( OUString(), *this ); + } +} + + +sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName ) +{ + ResultSetEntryGuard aGuard( *this ); + + // find the first column with the name columnName + 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 ); + assert(false); + return 0; // Never reached +} + +Reference< XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + +Reference< XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 /*columnIndex*/ ) +{ + ResultSetEntryGuard aGuard( *this ); + m_bWasNull = true; + return false; +} + + +sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 /*columnIndex*/ ) +{ + return 0; +} + + +Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 /*columnIndex*/ ) +{ + return Sequence< sal_Int8 >(); +} + + +Date SAL_CALL OResultSet::getDate( sal_Int32 /*columnIndex*/ ) +{ + return Date(); +} + + +double SAL_CALL OResultSet::getDouble( sal_Int32 /*columnIndex*/ ) +{ + return 0.0; +} + + +float SAL_CALL OResultSet::getFloat( sal_Int32 /*columnIndex*/ ) +{ + return 0; +} + + +sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 /*columnIndex*/ ) +{ + return 0; +} + + +sal_Int32 SAL_CALL OResultSet::getRow( ) +{ + ResultSetEntryGuard aGuard( *this ); + + SAL_INFO("connectivity.mork", "return = " << m_nRowPos); + return m_nRowPos; +} + + +sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 /*columnIndex*/ ) +{ + return sal_Int64(); +} + + +Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( ) +{ + ResultSetEntryGuard aGuard( *this ); + + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData( + m_pSQLIterator->getSelectColumns(), m_pSQLIterator->getTables().begin()->first, m_xTable.get(), determineReadOnly()); + return m_xMetaData; +} + +Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + +Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ ) +{ + return nullptr; +} + + +Any SAL_CALL OResultSet::getObject( sal_Int32 /*columnIndex*/, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + return Any(); +} + + +sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 /*columnIndex*/ ) +{ + return 0; +} + + +void OResultSet::checkIndex(sal_Int32 columnIndex ) +{ + if(columnIndex <= 0 || columnIndex > static_cast<sal_Int32>(m_xColumns->size())) + ::dbtools::throwInvalidIndexException(*this); +} + +sal_uInt32 OResultSet::currentRowCount() +{ + if ( m_bIsAlwaysFalseQuery ) + return 0; + //return 0;//m_aQuery.getRealRowCount() - deletedCount(); + // new implementation + return m_aQueryHelper.getResultCount(); +} + + +bool OResultSet::fetchCurrentRow( ) +{ + SAL_INFO("connectivity.mork", "m_nRowPos = " << m_nRowPos); + return fetchRow(getCurrentCardNumber()); +} + + +bool OResultSet::fetchRow(sal_Int32 cardNumber,bool bForceReload) +{ + SAL_INFO("connectivity.mork", "cardNumber = " << cardNumber); + if (!bForceReload) + { + // Check whether we've already fetched the row... + if ( !(*m_aRow)[0].isNull() && static_cast<sal_Int32>((*m_aRow)[0]) == cardNumber ) + return true; + } +// else +// m_aQuery.resyncRow(cardNumber); + + if ( !validRow( cardNumber ) ) + return false; + + (*m_aRow)[0] = cardNumber; + sal_Int32 nCount = m_aColumnNames.getLength(); + //m_RowStates = m_aQuery.getRowStates(cardNumber); + for( sal_Int32 i = 1; i <= nCount; i++ ) + { + if ( (*m_aRow)[i].isBound() ) + { + + // Everything in the addressbook is a string! + + if ( !m_aQueryHelper.getRowValue( (*m_aRow)[i], cardNumber, m_aColumnNames[i-1], DataType::VARCHAR )) + { + m_pStatement->getOwnConnection()->throwSQLException( m_aQueryHelper.getError(), *this ); + } + } + } + return true; + +} + + +const ORowSetValue& OResultSet::getValue(sal_Int32 cardNumber, sal_Int32 columnIndex ) +{ + if ( !fetchRow( cardNumber ) ) + { + OSL_FAIL("fetchRow() returned False" ); + m_bWasNull = true; + return *ODatabaseMetaDataResultSet::getEmptyValue(); + } + + m_bWasNull = (*m_aRow)[columnIndex].isNull(); + return (*m_aRow)[columnIndex]; + +} + + +OUString SAL_CALL OResultSet::getString( sal_Int32 columnIndex ) +{ + ResultSetEntryGuard aGuard( *this ); + + OSL_ENSURE(m_xColumns.is(), "Need the Columns!!"); + OSL_ENSURE(columnIndex <= static_cast<sal_Int32>(m_xColumns->size()), "Trying to access invalid columns number"); + checkIndex( columnIndex ); + + // If this query was sorted then we should have a valid KeySet, so use it + return getValue(getCurrentCardNumber(), mapColumn( columnIndex ) ); + +} + + +Time SAL_CALL OResultSet::getTime( sal_Int32 /*columnIndex*/ ) +{ + ResultSetEntryGuard aGuard( *this ); + return Time(); +} + + +DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 /*columnIndex*/ ) +{ + ResultSetEntryGuard aGuard( *this ); + return DateTime(); +} + + +sal_Bool SAL_CALL OResultSet::isBeforeFirst( ) +{ + ResultSetEntryGuard aGuard( *this ); + + // here you have to implement your movements + // return true means there is no data + return( m_nRowPos < 1 ); +} + +sal_Bool SAL_CALL OResultSet::isAfterLast( ) +{ + SAL_WARN("connectivity.mork", "OResultSet::isAfterLast() NOT IMPLEMENTED!"); + ResultSetEntryGuard aGuard( *this ); + + return m_nRowPos > currentRowCount(); +} + +sal_Bool SAL_CALL OResultSet::isFirst( ) +{ + ResultSetEntryGuard aGuard( *this ); + + return m_nRowPos == 1; +} + +sal_Bool SAL_CALL OResultSet::isLast( ) +{ + SAL_WARN("connectivity.mork", "OResultSet::isLast() NOT IMPLEMENTED!"); + ResultSetEntryGuard aGuard( *this ); + +// return sal_True; + return m_nRowPos == currentRowCount(); +} + +void SAL_CALL OResultSet::beforeFirst( ) +{ + ResultSetEntryGuard aGuard( *this ); + + // move before the first row so that isBeforeFirst returns false + if ( first() ) + previous(); +} + +void SAL_CALL OResultSet::afterLast( ) +{ + ResultSetEntryGuard aGuard( *this ); + + if(last()) + next(); +} + + +void SAL_CALL OResultSet::close() +{ + dispose(); +} + + +sal_Bool SAL_CALL OResultSet::first( ) +{ + return seekRow( FIRST_POS ); +} + + +sal_Bool SAL_CALL OResultSet::last( ) +{ + return seekRow( LAST_POS ); +} + +sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row ) +{ + return seekRow( ABSOLUTE_POS, row ); +} + +sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row ) +{ + return seekRow( RELATIVE_POS, row ); +} + +sal_Bool SAL_CALL OResultSet::previous( ) +{ + ResultSetEntryGuard aGuard( *this ); + return seekRow( PRIOR_POS ); +} + +Reference< XInterface > SAL_CALL OResultSet::getStatement( ) +{ + ResultSetEntryGuard aGuard( *this ); + return m_xStatement; +} + + +sal_Bool SAL_CALL OResultSet::rowDeleted( ) +{ + SAL_WARN("connectivity.mork", "OResultSet::rowDeleted() NOT IMPLEMENTED!"); + ResultSetEntryGuard aGuard( *this ); + return true;//return ((m_RowStates & RowStates_Deleted) == RowStates_Deleted) ; +} + +sal_Bool SAL_CALL OResultSet::rowInserted( ) +{ + SAL_WARN("connectivity.mork", "OResultSet::rowInserted() NOT IMPLEMENTED!"); + ResultSetEntryGuard aGuard( *this ); + return true;//return ((m_RowStates & RowStates_Inserted) == RowStates_Inserted); +} + +sal_Bool SAL_CALL OResultSet::rowUpdated( ) +{ + SAL_WARN("connectivity.mork", "OResultSet::rowUpdated() NOT IMPLEMENTED!"); + ResultSetEntryGuard aGuard( *this ); + return true;// return ((m_RowStates & RowStates_Updated) == RowStates_Updated) ; +} + + +sal_Bool SAL_CALL OResultSet::next( ) +{ + return seekRow( NEXT_POS ); +} + + +sal_Bool SAL_CALL OResultSet::wasNull( ) +{ + ResultSetEntryGuard aGuard( *this ); + + return m_bWasNull; +} + + +void SAL_CALL OResultSet::cancel( ) +{ +} + +void SAL_CALL OResultSet::clearWarnings( ) +{ +} + +Any SAL_CALL OResultSet::getWarnings( ) +{ + return Any(); +} + +void SAL_CALL OResultSet::refreshRow( ) +{ + if (fetchRow(getCurrentCardNumber(),true)) { + //force fetch current row will cause we lose all change to the current row + m_pStatement->getOwnConnection()->throwSQLException( STR_ERROR_REFRESH_ROW, *this ); + } +} + +IPropertyArrayHelper* OResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps(5); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), + PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + return new OPropertyArrayHelper(aProps); +} + +IPropertyArrayHelper & OResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool OResultSet::convertFastPropertyValue( + Any & /*rConvertedValue*/, + Any & /*rOldValue*/, + sal_Int32 nHandle, + const Any& /*rValue*/ ) +{ + OSL_FAIL( "OResultSet::convertFastPropertyValue: not implemented!" ); + switch(nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + default: + ; + } + return false; +} + +void OResultSet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const Any& /*rValue*/ + ) +{ + OSL_FAIL( "OResultSet::setFastPropertyValue_NoBroadcast: not implemented!" ); + switch(nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw Exception("cannot set prop " + OUString::number(nHandle), nullptr); + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_FETCHSIZE: + break; + default: + ; + } +} + +void OResultSet::getFastPropertyValue( + Any& rValue, + sal_Int32 nHandle + ) const +{ + switch(nHandle) + { + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= sal_Int32(ResultSetConcurrency::UPDATABLE); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= m_nResultSetType; + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= m_nFetchDirection; + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= sal_Int32(0); + break; + case PROPERTY_ID_ISBOOKMARKABLE: + const_cast< OResultSet* >( this )->determineReadOnly(); + rValue <<= (m_bIsReadOnly == TRISTATE_FALSE); + break; + } +} + +void SAL_CALL OResultSet::acquire() throw() +{ + OResultSet_BASE::acquire(); +} + +void SAL_CALL OResultSet::release() throw() +{ + OResultSet_BASE::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + + +void OResultSet::parseParameter( const OSQLParseNode* pNode, OUString& rMatchString ) +{ + OSL_ENSURE(pNode->count() > 0,"Error parsing parameter in Parse Tree"); + OSQLParseNode *pMark = pNode->getChild(0); + + // Initialize to empty string + rMatchString.clear(); + + OUString aParameterName; + if (SQL_ISPUNCTUATION(pMark,"?")) { + aParameterName = "?"; + } + else if (SQL_ISPUNCTUATION(pMark,":")) { + aParameterName = pNode->getChild(1)->getTokenValue(); + } + // XXX - Now we know name, what's value???? + m_nParamIndex ++; + SAL_INFO( + "connectivity.mork", + "Parameter name [" << m_nParamIndex << "]: " << aParameterName); + + if ( m_aParameterRow.is() ) { + OSL_ENSURE( m_nParamIndex < static_cast<sal_Int32>(m_aParameterRow->size()) + 1, "More parameters than values found" ); + rMatchString = (*m_aParameterRow)[static_cast<sal_uInt16>(m_nParamIndex)]; + SAL_INFO("connectivity.mork", "Prop Value: " << rMatchString); + } + else { + SAL_INFO("connectivity.mork", "Prop Value: Invalid ParameterRow!"); + } +} + +#define WILDCARD "%" +#define ALT_WILDCARD "*" +static const sal_Unicode MATCHCHAR = '_'; + +void OResultSet::analyseWhereClause( const OSQLParseNode* parseTree, + MQueryExpression &queryExpression) +{ + OUString columnName; + MQueryOp::cond_type op( MQueryOp::Is ); + OUString matchString; + + if ( parseTree == nullptr ) + return; + + if ( m_pSQLIterator->getParseTree() != nullptr ) { + ::rtl::Reference<OSQLColumns> xColumns = m_pSQLIterator->getParameters(); + if(xColumns.is()) + { + OUString aColName, aParameterValue; + sal_Int32 i = 1; + for (auto const& column : *xColumns) + { + column->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName; + SAL_INFO("connectivity.mork", "Prop Column Name: " << aColName); + if ( m_aParameterRow.is() ) { + aParameterValue = (*m_aParameterRow)[static_cast<sal_uInt16>(i)]; + SAL_INFO("connectivity.mork", "Prop Value: " << aParameterValue); + } + else { + SAL_INFO("connectivity.mork", "Prop Value: Invalid ParameterRow!"); + } + i++; + } + } + + } + + if ( SQL_ISRULE(parseTree,where_clause) ) + { + // Reset Parameter Counter + resetParameters(); + analyseWhereClause( parseTree->getChild( 1 ), queryExpression ); + } + else if ( parseTree->count() == 3 && // Handle ()'s + SQL_ISPUNCTUATION(parseTree->getChild(0),"(") && + SQL_ISPUNCTUATION(parseTree->getChild(2),")")) + { + MQueryExpression *subExpression = new MQueryExpression(); + analyseWhereClause( parseTree->getChild( 1 ), *subExpression ); + queryExpression.addExpression( subExpression ); + } + else if ((SQL_ISRULE(parseTree,search_condition) || SQL_ISRULE(parseTree,boolean_term)) + && parseTree->count() == 3) // Handle AND/OR + { + // TODO - Need to take care or AND, for now match is always OR + analyseWhereClause( parseTree->getChild( 0 ), queryExpression ); + analyseWhereClause( parseTree->getChild( 2 ), queryExpression ); + + if (SQL_ISTOKEN(parseTree->getChild(1),OR)) { // OR-Operator + queryExpression.setExpressionCondition( MQueryExpression::OR ); + } + else if (SQL_ISTOKEN(parseTree->getChild(1),AND)) { // AND-Operator + queryExpression.setExpressionCondition( MQueryExpression::AND ); + } + else { + OSL_FAIL("analyseSQL: Error in Parse Tree"); + } + } + else if (SQL_ISRULE(parseTree,comparison_predicate)) + { + OSL_ENSURE(parseTree->count() == 3, "Error parsing COMPARE predicate"); + if (!(SQL_ISRULE(parseTree->getChild(0),column_ref) || + parseTree->getChild(2)->getNodeType() == SQLNodeType::String || + parseTree->getChild(2)->getNodeType() == SQLNodeType::IntNum || + parseTree->getChild(2)->getNodeType() == SQLNodeType::ApproxNum || + SQL_ISTOKEN(parseTree->getChild(2),TRUE) || + SQL_ISTOKEN(parseTree->getChild(2),FALSE) || + SQL_ISRULE(parseTree->getChild(2),parameter) || + // odbc date + (SQL_ISRULE(parseTree->getChild(2),set_fct_spec) && SQL_ISPUNCTUATION(parseTree->getChild(2)->getChild(0),"{")))) + { + m_pStatement->getOwnConnection()->throwSQLException( STR_QUERY_TOO_COMPLEX, *this ); + } + + OSQLParseNode *pPrec = parseTree->getChild(1); + if (pPrec->getNodeType() == SQLNodeType::Equal) + op = MQueryOp::Is; + else if (pPrec->getNodeType() == SQLNodeType::NotEqual) + op = MQueryOp::IsNot; + + OUString sTableRange; + if(SQL_ISRULE(parseTree->getChild(0),column_ref)) + m_pSQLIterator->getColumnRange(parseTree->getChild(0),columnName,sTableRange); + else if(parseTree->getChild(0)->isToken()) + columnName = parseTree->getChild(0)->getTokenValue(); + + if ( SQL_ISRULE(parseTree->getChild(2),parameter) ) { + parseParameter( parseTree->getChild(2), matchString ); + } + else { + matchString = parseTree->getChild(2)->getTokenValue(); + } + + if ( columnName == "0" && op == MQueryOp::Is && matchString == "1" ) { + m_bIsAlwaysFalseQuery = true; + } + queryExpression.addExpression( new MQueryExpressionString( columnName, op, matchString )); + } + else if (SQL_ISRULE(parseTree,like_predicate)) + { + OSL_ENSURE(parseTree->count() == 2, "Error parsing LIKE predicate"); + + if ( !SQL_ISRULE(parseTree->getChild(0), column_ref) ) + { + m_pStatement->getOwnConnection()->throwSQLException( STR_QUERY_INVALID_LIKE_COLUMN, *this ); + } + + + OSQLParseNode *pColumn; + OSQLParseNode *pAtom; + OSQLParseNode *pOptEscape; + const OSQLParseNode* pPart2 = parseTree->getChild(1); + pColumn = parseTree->getChild(0); // Match Item + pAtom = pPart2->getChild(static_cast<sal_uInt32>(pPart2->count()-2)); // Match String + pOptEscape = pPart2->getChild(static_cast<sal_uInt32>(pPart2->count()-1)); // Opt Escape Rule + (void)pOptEscape; + const bool bNot = SQL_ISTOKEN(pPart2->getChild(0), NOT); + + if (!(pAtom->getNodeType() == SQLNodeType::String || + pAtom->getNodeType() == SQLNodeType::Name || + SQL_ISRULE(pAtom,parameter) || + ( pAtom->getChild(0) && pAtom->getChild(0)->getNodeType() == SQLNodeType::Name ) || + ( pAtom->getChild(0) && pAtom->getChild(0)->getNodeType() == SQLNodeType::String ) + ) ) + { + m_pStatement->getOwnConnection()->throwSQLException( STR_QUERY_INVALID_LIKE_STRING, *this ); + } + + OUString sTableRange; + if(SQL_ISRULE(pColumn,column_ref)) + m_pSQLIterator->getColumnRange(pColumn,columnName,sTableRange); + + SAL_INFO("connectivity.mork", "ColumnName = " << columnName); + + if ( SQL_ISRULE(pAtom,parameter) ) { + parseParameter( pAtom, matchString ); + // Replace all '*' with '%' : UI Usually does this but not with + // Parameters for some reason. + matchString = matchString.replaceAll( ALT_WILDCARD, WILDCARD ); + } + else + { + matchString = pAtom->getTokenValue(); + } + + // Determine where '%' character is... + + if ( matchString == WILDCARD ) + { + // String containing only a '%' and nothing else + op = MQueryOp::Exists; + // Will be ignored for Exists case, but clear anyway. + matchString.clear(); + } + else if ( matchString.indexOf ( WILDCARD ) == -1 && + matchString.indexOf ( MATCHCHAR ) == -1 ) + { + // Simple string , eg. "to match" + if ( bNot ) + op = MQueryOp::DoesNotContain; + else + op = MQueryOp::Contains; + } + else if ( matchString.startsWith( WILDCARD ) + && matchString.endsWith( WILDCARD ) + && matchString.indexOf ( WILDCARD, 1 ) == matchString.lastIndexOf ( WILDCARD ) + && matchString.indexOf( MATCHCHAR ) == -1 + ) + { + // Relatively simple "%string%" - ie, contains... + // Cut '%' from front and rear + matchString = matchString.replaceAt( 0, 1, OUString() ); + matchString = matchString.replaceAt( matchString.getLength() -1 , 1, OUString() ); + + if (bNot) + op = MQueryOp::DoesNotContain; + else + op = MQueryOp::Contains; + } + else if ( bNot ) + { + // We currently can't handle a 'NOT LIKE' when there are '%' or + // '_' dispersed throughout + m_pStatement->getOwnConnection()->throwSQLException( STR_QUERY_NOT_LIKE_TOO_COMPLEX, *this ); + } + else + { + if ( (matchString.indexOf ( WILDCARD ) == matchString.lastIndexOf ( WILDCARD )) + && matchString.indexOf( MATCHCHAR ) == -1 + ) + { + // One occurrence of '%' - no '_' matches... + if ( matchString.startsWith( WILDCARD ) ) + { + op = MQueryOp::EndsWith; + matchString = matchString.replaceAt( 0, 1, OUString()); + } + else if ( matchString.indexOf ( WILDCARD ) == matchString.getLength() -1 ) + { + op = MQueryOp::BeginsWith; + matchString = matchString.replaceAt( matchString.getLength() -1 , 1, OUString() ); + } + else + { + sal_Int32 pos = matchString.indexOf ( WILDCARD ); + matchString = matchString.replaceAt( pos, 1, ".*" ); + op = MQueryOp::RegExp; + } + + } + else + { + // Most Complex, need to use a RE + sal_Int32 pos; + while ( (pos = matchString.indexOf ( WILDCARD )) != -1 ) + { + matchString = matchString.replaceAt( pos, 1, ".*" ); + } + + while ( (pos = matchString.indexOf( MATCHCHAR )) != -1 ) + { + matchString = matchString.replaceAt( pos, 1, "." ); + } + + op = MQueryOp::RegExp; + } + } + + queryExpression.addExpression( new MQueryExpressionString( columnName, op, matchString )); + } + else if (SQL_ISRULE(parseTree,test_for_null)) + { + OSL_ENSURE(parseTree->count() == 2,"Error in ParseTree"); + const OSQLParseNode* pPart2 = parseTree->getChild(1); + OSL_ENSURE(SQL_ISTOKEN(pPart2->getChild(0),IS),"Error in ParseTree"); + + if (!SQL_ISRULE(parseTree->getChild(0),column_ref)) + { + m_pStatement->getOwnConnection()->throwSQLException( STR_QUERY_INVALID_IS_NULL_COLUMN, *this ); + } + + if (SQL_ISTOKEN(pPart2->getChild(1),NOT)) + { + op = MQueryOp::Exists; + } + else + { + op = MQueryOp::DoesNotExist; + } + + OUString sTableRange; + m_pSQLIterator->getColumnRange(parseTree->getChild(0),columnName,sTableRange); + + queryExpression.addExpression( new MQueryExpressionString( columnName, op )); + } + else + { + SAL_WARN("connectivity.mork", "Unexpected statement!!!" ); + m_pStatement->getOwnConnection()->throwSQLException( STR_QUERY_TOO_COMPLEX, *this ); + } +} + +void OResultSet::fillRowData() +{ + OSL_ENSURE( m_pStatement, "Require a statement" ); + + MQueryExpression queryExpression; + + OConnection* pConnection = static_cast<OConnection*>(m_pStatement->getConnection().get()); + m_xColumns = m_pSQLIterator->getSelectColumns(); + + OSL_ENSURE(m_xColumns.is(), "Need the Columns!!"); + + const OUString sPropertyName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME); + OUString sName; + sal_Int32 i = 1; + for (const auto& rxColumn : *m_xColumns) + { + rxColumn->getPropertyValue(sPropertyName) >>= sName; + SAL_INFO( + "connectivity.mork", "Query Columns : (" << i << ") " << sName); + i++; + } + + // Generate Match Conditions for Query + const OSQLParseNode* pParseTree = m_pSQLIterator->getWhereTree(); + + m_bIsAlwaysFalseQuery = false; + if ( pParseTree != nullptr ) + { + // Extract required info + + analyseWhereClause( pParseTree, queryExpression ); + } + // If the query is a 0=1 then set Row count to 0 and return + if ( m_bIsAlwaysFalseQuery ) + { + m_bIsReadOnly = TRISTATE_TRUE; + return; + } + + OUString aStr( m_xTable->getName() ); + m_aQueryHelper.setAddressbook( aStr ); + + sal_Int32 rv = m_aQueryHelper.executeQuery(pConnection, queryExpression); + if ( rv == -1 ) { + m_pStatement->getOwnConnection()->throwSQLException( STR_ERR_EXECUTING_QUERY, *this ); + } + + if (m_aQueryHelper.hadError()) + { + m_pStatement->getOwnConnection()->throwSQLException( m_aQueryHelper.getError(), *this ); + } + + //determine whether the address book is readonly + determineReadOnly(); + + SAL_INFO("connectivity.mork", "executeQuery returned " << rv); +} + + +static bool matchRow( OValueRow const & row1, OValueRow const & row2 ) +{ + // the first column is the bookmark column + return std::equal(std::next(row1->begin()), row1->end(), std::next(row2->begin()), + [](const ORowSetValue& a, const ORowSetValue& b) { return !a.isBound() || a == b; }); +} + +sal_Int32 OResultSet::getRowForCardNumber(sal_Int32 nCardNum) +{ + SAL_INFO("connectivity.mork", "nCardNum = " << nCardNum); + + if ( m_pKeySet.is() ) + { + sal_Int32 nPos; + for(nPos=0;nPos < static_cast<sal_Int32>(m_pKeySet->size());nPos++) + { + if (nCardNum == (*m_pKeySet)[nPos]) + { + SAL_INFO("connectivity.mork", "return = " << nPos+1); + return nPos+1; + } + } + } + + m_pStatement->getOwnConnection()->throwSQLException( STR_INVALID_BOOKMARK, *this ); + + return 0; +} + +void OResultSet::executeQuery() +{ + ResultSetEntryGuard aGuard( *this ); + + OSL_ENSURE( m_xTable.is(), "Need a Table object"); + if(!m_xTable.is()) + { + const OSQLTables& rTabs = m_pSQLIterator->getTables(); + if (rTabs.empty() || !rTabs.begin()->second.is()) + m_pStatement->getOwnConnection()->throwSQLException( STR_QUERY_TOO_COMPLEX, *this ); + + m_xTable = static_cast< OTable* > (rTabs.begin()->second.get()); + } + + m_nRowPos = 0; + + fillRowData(); + + OSL_ENSURE(m_xColumns.is(), "Need the Columns!!"); + + switch( m_pSQLIterator->getStatementType() ) + { + case OSQLStatementType::Select: + { + if(m_bIsAlwaysFalseQuery) { + break; + } + else if(isCount()) + { + m_pStatement->getOwnConnection()->throwSQLException( STR_NO_COUNT_SUPPORT, *this ); + } + else + { + bool bDistinct = false; + OSQLParseNode *pDistinct = m_pParseTree->getChild(1); + if (pDistinct && pDistinct->getTokenID() == SQL_TOKEN_DISTINCT) + { + if(!IsSorted()) + { + m_aOrderbyColumnNumber.push_back(m_aColMapping[1]); + m_aOrderbyAscending.push_back(TAscendingOrder::DESC); + } + bDistinct = true; + } + + OSortIndex::TKeyTypeVector eKeyType(m_aOrderbyColumnNumber.size()); + std::vector<sal_Int16>::size_type index = 0; + for (const auto& rColIndex : m_aOrderbyColumnNumber) + { + OSL_ENSURE(static_cast<sal_Int32>(m_aRow->size()) > rColIndex,"Invalid Index"); + switch ((m_aRow->begin()+rColIndex)->getTypeKind()) + { + case DataType::CHAR: + case DataType::VARCHAR: + eKeyType[index] = OKeyType::String; + break; + + case DataType::OTHER: + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + case DataType::BIT: + eKeyType[index] = OKeyType::Double; + break; + + // Other types aren't implemented (so they are always FALSE) + default: + eKeyType[index] = OKeyType::NONE; + OSL_FAIL("MResultSet::executeQuery: Order By Data Type not implemented"); + break; + } + ++index; + } + + if (IsSorted()) + { + // Implement Sorting + + // So that we can sort we need to wait until the executed + // query to the mozilla addressbooks has returned all + // values. + + OSortIndex aSortIndex(eKeyType,m_aOrderbyAscending); + +#if OSL_DEBUG_LEVEL > 0 + for ( std::vector<sal_Int32>::size_type i = 0; i < m_aColMapping.size(); i++ ) + SAL_INFO( + "connectivity.mork", + "Mapped: " << i << " -> " << m_aColMapping[i]); +#endif + for ( sal_Int32 nRow = 1; nRow <= m_aQueryHelper.getResultCount(); nRow++ ) { + + std::unique_ptr<OKeyValue> pKeyValue = OKeyValue::createKeyValue(nRow); + + for (const auto& rColIndex : m_aOrderbyColumnNumber) + { + const ORowSetValue& value = getValue(nRow, rColIndex); + + SAL_INFO( + "connectivity.mork", + "Adding Value: (" << nRow << "," << rColIndex + << ") : " << value.getString()); + + pKeyValue->pushKey(new ORowSetValueDecorator(value)); + } + + aSortIndex.AddKeyValue( std::move(pKeyValue) ); + } + + m_pKeySet = aSortIndex.CreateKeySet(); + m_CurrentRowCount = static_cast<sal_Int32>(m_pKeySet->size()); +#if OSL_DEBUG_LEVEL > 0 + for( OKeySet::size_type i = 0; i < m_pKeySet->size(); i++ ) + SAL_INFO( + "connectivity.mork", + "Sorted: " << i << " -> " << (*m_pKeySet)[i]); +#endif + + beforeFirst(); // Go back to start + } + else //we always need m_pKeySet now + m_pKeySet = new OKeySet(); + + // Handle the DISTINCT case + if ( bDistinct && m_pKeySet.is() ) + { + OValueRow aSearchRow = new OValueVector( m_aRow->size() ); + + for(sal_Int32 & i : *m_pKeySet) + { + fetchRow( i ); // Fills m_aRow + if ( matchRow( m_aRow, aSearchRow ) ) + { + i = 0; // Marker for later to be removed + } + else + { + // They don't match, so it's not a duplicate. + // Use the current Row as the next one to match against + *aSearchRow = *m_aRow; + } + } + // Now remove any keys marked with a 0 + m_pKeySet->erase(std::remove_if(m_pKeySet->begin(),m_pKeySet->end() + ,[](sal_Int32 n) { return n == 0; }) + ,m_pKeySet->end()); + + } + } + } break; + + case OSQLStatementType::Update: + case OSQLStatementType::Delete: + case OSQLStatementType::Insert: + break; + default: + m_pStatement->getOwnConnection()->throwSQLException( STR_STMT_TYPE_NOT_SUPPORTED, *this ); + break; + } +} + +void OResultSet::setBoundedColumns(const OValueRow& _rRow, + const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns, + const Reference<XIndexAccess>& _xNames, + bool _bSetColumnMapping, + const Reference<XDatabaseMetaData>& _xMetaData, + std::vector<sal_Int32>& _rColMapping) +{ + ::comphelper::UStringMixEqual aCase(_xMetaData->supportsMixedCaseQuotedIdentifiers()); + + Reference<XPropertySet> xTableColumn; + OUString sTableColumnName, sSelectColumnRealName; + + const OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME); + const OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME); + + std::vector< OUString> aColumnNames; + aColumnNames.reserve(_rxColumns->size()); + OValueVector::iterator aRowIter = _rRow->begin()+1; + for (sal_Int32 i=0; // the first column is the bookmark column + aRowIter != _rRow->end(); + ++i, ++aRowIter + ) + { + try + { + // get the table column and its name + _xNames->getByIndex(i) >>= xTableColumn; + OSL_ENSURE(xTableColumn.is(), "OResultSet::setBoundedColumns: invalid table column!"); + if (xTableColumn.is()) + xTableColumn->getPropertyValue(sName) >>= sTableColumnName; + else + sTableColumnName.clear(); + + // look if we have such a select column + // TODO: would like to have a O(log n) search here ... + sal_Int32 nColumnPos = 0; + for (const auto& rxColumn : *_rxColumns) + { + if ( nColumnPos < static_cast<sal_Int32>(aColumnNames.size()) ) + sSelectColumnRealName = aColumnNames[nColumnPos]; + else + { + if(rxColumn->getPropertySetInfo()->hasPropertyByName(sRealName)) + rxColumn->getPropertyValue(sRealName) >>= sSelectColumnRealName; + else + rxColumn->getPropertyValue(sName) >>= sSelectColumnRealName; + aColumnNames.push_back(sSelectColumnRealName); + } + + if (aCase(sTableColumnName, sSelectColumnRealName)) + { + if(_bSetColumnMapping) + { + sal_Int32 nSelectColumnPos = nColumnPos + 1; + // the getXXX methods are 1-based ... + sal_Int32 nTableColumnPos = i + 1; + // get first table column is the bookmark column + + SAL_INFO( + "connectivity.mork", + "Set Col Mapping: " << nSelectColumnPos << " -> " + << nTableColumnPos); + _rColMapping[nSelectColumnPos] = nTableColumnPos; + } + + aRowIter->setBound(true); + aRowIter->setTypeKind(DataType::VARCHAR); + } + + ++nColumnPos; + } + } + catch (Exception&) + { + OSL_FAIL("OResultSet::setBoundedColumns: caught an Exception!"); + } + } +} + + +bool OResultSet::isCount() const +{ + return (m_pParseTree && + m_pParseTree->count() > 2 && + SQL_ISRULE(m_pParseTree->getChild(2),scalar_exp_commalist) && + SQL_ISRULE(m_pParseTree->getChild(2)->getChild(0),derived_column) && + SQL_ISRULE(m_pParseTree->getChild(2)->getChild(0)->getChild(0),general_set_fct) && + m_pParseTree->getChild(2)->getChild(0)->getChild(0)->count() == 4 + ); +} + + +// Check for valid row in m_aQuery + +bool OResultSet::validRow( sal_uInt32 nRow) +{ + sal_Int32 nNumberOfRecords = m_aQueryHelper.getResultCount(); + + if (( nRow == 0 ) || + ( nRow > o3tl::make_unsigned(nNumberOfRecords)) ){ + SAL_INFO("connectivity.mork", "validRow(" << nRow << "): return False"); + return false; + } + SAL_INFO("connectivity.mork", "validRow(" << nRow << "): return True"); + + return true; +} + +void OResultSet::fillKeySet(sal_Int32 nMaxCardNumber) +{ + impl_ensureKeySet(); + if (m_CurrentRowCount < nMaxCardNumber) + { + sal_Int32 nKeyValue; + if ( static_cast<sal_Int32>(m_pKeySet->capacity()) < nMaxCardNumber ) + m_pKeySet->reserve(nMaxCardNumber + 20 ); + + for (nKeyValue = m_CurrentRowCount+1; nKeyValue <= nMaxCardNumber; nKeyValue ++) + m_pKeySet->push_back( nKeyValue ); + m_CurrentRowCount = nMaxCardNumber; + } +} + +sal_Int32 OResultSet::deletedCount() +{ + impl_ensureKeySet(); + return m_CurrentRowCount - static_cast<sal_Int32>(m_pKeySet->size()); + +} + +bool OResultSet::seekRow( eRowPosition pos, sal_Int32 nOffset ) +{ + ResultSetEntryGuard aGuard( *this ); + if ( !m_pKeySet.is() ) + m_pStatement->getOwnConnection()->throwSQLException( STR_ILLEGAL_MOVEMENT, *this ); + + sal_Int32 nNumberOfRecords = m_aQueryHelper.getResultCount(); + sal_Int32 nRetrievedRows = currentRowCount(); + sal_Int32 nCurPos = m_nRowPos; + + SAL_INFO("connectivity.mork", "nCurPos = " << nCurPos); + switch( pos ) { + case NEXT_POS: + nCurPos++; + break; + case PRIOR_POS: + if ( nCurPos > 0 ) + nCurPos--; + break; + case FIRST_POS: + nCurPos = 1; + break; + case LAST_POS: + nCurPos = nRetrievedRows; + break; + case ABSOLUTE_POS: + nCurPos = nOffset; + break; + case RELATIVE_POS: + nCurPos += sal_uInt32( nOffset ); + break; + } + + if ( nCurPos <= 0 ) { + m_nRowPos = 0; + SAL_INFO( + "connectivity.mork", "return False, m_nRowPos = " << m_nRowPos); + return false; + } + sal_Int32 nCurCard; + if ( nCurPos < static_cast<sal_Int32>(m_pKeySet->size()) ) //The requested row is exist in m_pKeySet, so we just use it + { + nCurCard = (*m_pKeySet)[nCurPos-1]; + } + else //The requested row has not been retrieved until now. We should get the right card for it. + nCurCard = nCurPos + deletedCount(); + + if ( nCurCard > nNumberOfRecords) { + fillKeySet(nNumberOfRecords); + m_nRowPos = static_cast<sal_uInt32>(m_pKeySet->size() + 1); + SAL_INFO( + "connectivity.mork", "return False, m_nRowPos = " << m_nRowPos); + return false; + } + //Insert new retrieved items for later use + fillKeySet(nNumberOfRecords); + m_nRowPos = static_cast<sal_uInt32>(nCurPos); + SAL_INFO("connectivity.mork", "return True, m_nRowPos = " << m_nRowPos); + fetchCurrentRow(); + return true; +} + +void OResultSet::setColumnMapping(const std::vector<sal_Int32>& _aColumnMapping) +{ + m_aColMapping = _aColumnMapping; +#if OSL_DEBUG_LEVEL > 0 + for ( size_t i = 0; i < m_aColMapping.size(); i++ ) + SAL_INFO( + "connectivity.mork", + "Set Mapped: " << i << " -> " << m_aColMapping[i]); +#endif +} + + +css::uno::Any OResultSet::getBookmark( ) +{ + SAL_INFO("connectivity.mork", "m_nRowPos = " << m_nRowPos); + ResultSetEntryGuard aGuard( *this ); + if ( !fetchCurrentRow() ) { + m_pStatement->getOwnConnection()->throwSQLException( STR_ERROR_GET_ROW, *this ); + } + + OSL_ENSURE((!m_aRow->isDeleted()),"getBookmark called for deleted row"); + return makeAny(static_cast<sal_Int32>((*m_aRow)[0])); +} +sal_Bool OResultSet::moveToBookmark( const css::uno::Any& bookmark ) +{ + ResultSetEntryGuard aGuard( *this ); + SAL_INFO( + "connectivity.mork", "bookmark = " << comphelper::getINT32(bookmark)); + sal_Int32 nCardNum = comphelper::getINT32(bookmark); + m_nRowPos = getRowForCardNumber(nCardNum); + fetchCurrentRow(); + return true; +} +sal_Bool OResultSet::moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) +{ + ResultSetEntryGuard aGuard( *this ); + SAL_INFO( + "connectivity.mork", + "bookmark = " << comphelper::getINT32(bookmark) << " rows= " << rows); + sal_Int32 nCardNum = comphelper::getINT32(bookmark); + m_nRowPos = getRowForCardNumber(nCardNum); + return seekRow(RELATIVE_POS,rows ); +} +sal_Int32 OResultSet::compareBookmarks( const css::uno::Any& lhs, const css::uno::Any& rhs ) +{ + ResultSetEntryGuard aGuard( *this ); + SAL_INFO("connectivity.mork", "m_nRowPos = " << m_nRowPos); + sal_Int32 nFirst=0; + sal_Int32 nSecond=0; + sal_Int32 nResult=0; + + if ( !( lhs >>= nFirst ) || !( rhs >>= nSecond ) ) { + m_pStatement->getOwnConnection()->throwSQLException( STR_INVALID_BOOKMARK, *this ); + } + + if(nFirst < nSecond) + nResult = CompareBookmark::LESS; + else if(nFirst > nSecond) + nResult = CompareBookmark::GREATER; + else + nResult = CompareBookmark::EQUAL; + + return nResult; +} +sal_Bool OResultSet::hasOrderedBookmarks( ) +{ + ResultSetEntryGuard aGuard( *this ); + SAL_INFO("connectivity.mork", "m_nRowPos = " << m_nRowPos); + return true; +} +sal_Int32 OResultSet::hashBookmark( const css::uno::Any& bookmark ) +{ + ResultSetEntryGuard aGuard( *this ); + SAL_INFO("connectivity.mork", "m_nRowPos = " << m_nRowPos); + return comphelper::getINT32(bookmark); +} + +sal_Int32 OResultSet::getCurrentCardNumber() +{ + if ( ( m_nRowPos == 0 ) || !m_pKeySet.is() ) + return 0; + if (m_pKeySet->size() < m_nRowPos) + return 0; + return (*m_pKeySet)[m_nRowPos-1]; +} +void OResultSet::checkPendingUpdate() +{ + OSL_FAIL( "OResultSet::checkPendingUpdate() not implemented" ); +/* + const sal_Int32 nCurrentRow = getCurrentCardNumber(); + + if ((m_nNewRow && nCurrentRow != m_nNewRow) + || ( m_nUpdatedRow && m_nUpdatedRow != nCurrentRow)) + { + const OUString sError( m_pStatement->getOwnConnection()->getResources().getResourceStringWithSubstitution( + STR_COMMIT_ROW, + "$position$", OUString::valueOf(nCurrentRow) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } +*/ + +} +void OResultSet::updateValue(sal_Int32 columnIndex ,const ORowSetValue& x) +{ + SAL_INFO("connectivity.mork", "m_nRowPos = " << m_nRowPos); + ResultSetEntryGuard aGuard( *this ); + if ( !fetchCurrentRow() ) { + m_pStatement->getOwnConnection()->throwSQLException( STR_ERROR_GET_ROW, *this ); + } + + checkPendingUpdate(); + + checkIndex(columnIndex ); + columnIndex = mapColumn(columnIndex); + + (*m_aRow)[columnIndex].setBound(true); + (*m_aRow)[columnIndex] = x; +} + + +void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex ) +{ + SAL_INFO("connectivity.mork", "m_nRowPos = " << m_nRowPos); + ResultSetEntryGuard aGuard( *this ); + if ( !fetchCurrentRow() ) + m_pStatement->getOwnConnection()->throwSQLException( STR_ERROR_GET_ROW, *this ); + + checkPendingUpdate(); + checkIndex(columnIndex ); + columnIndex = mapColumn(columnIndex); + + (*m_aRow)[columnIndex].setBound(true); + (*m_aRow)[columnIndex].setNull(); +} + + +void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) +{ + updateValue(columnIndex, static_cast<bool>(x)); +} + +void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateLong( sal_Int32 /*columnIndex*/, sal_Int64 /*x*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::updateLong", *this ); +} + +void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x ) +{ + updateValue(columnIndex,x); +} + +void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) +{ + updateValue(columnIndex,x); +} + + +void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + ResultSetEntryGuard aGuard( *this ); + + if(!x.is()) + ::dbtools::throwFunctionSequenceException(*this); + + Sequence<sal_Int8> aSeq; + x->readBytes(aSeq,length); + updateValue(columnIndex,aSeq); +} + +void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + updateBinaryStream(columnIndex,x,length); +} + +void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x ) +{ + if (!::dbtools::implUpdateObject(this, columnIndex, x)) + { + const OUString sError( m_pStatement->getOwnConnection()->getResources().getResourceStringWithSubstitution( + STR_COLUMN_NOT_UPDATEABLE, + "$position$", OUString::number(columnIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } // if (!::dbtools::implUpdateObject(this, columnIndex, x)) + } + + +void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ ) +{ + if (!::dbtools::implUpdateObject(this, columnIndex, x)) + { + const OUString sError( m_pStatement->getOwnConnection()->getResources().getResourceStringWithSubstitution( + STR_COLUMN_NOT_UPDATEABLE, + "$position$", OUString::number(columnIndex) + ) ); + ::dbtools::throwGenericSQLException(sError,*this); + } +} + +// XResultSetUpdate + +void SAL_CALL OResultSet::insertRow( ) +{ + ResultSetEntryGuard aGuard( *this ); + SAL_INFO("connectivity.mork", "in, m_nRowPos = " << m_nRowPos); +// m_RowStates = RowStates_Inserted; + updateRow(); + //m_aQueryHelper.setRowStates(getCurrentCardNumber(),m_RowStates); + SAL_INFO("connectivity.mork", "out, m_nRowPos = " << m_nRowPos); +} + +void SAL_CALL OResultSet::updateRow( ) +{ + OSL_FAIL( "OResultSet::updateRow( ) not implemented" ); +} + +void SAL_CALL OResultSet::deleteRow( ) +{ + OSL_FAIL( "OResultSet::deleteRow( ) not implemented" ); +} + +void SAL_CALL OResultSet::cancelRowUpdates( ) +{ + OSL_FAIL( "OResultSet::cancelRowUpdates( ) not implemented" ); +} + +void SAL_CALL OResultSet::moveToInsertRow( ) +{ + OSL_FAIL( "OResultSet::moveToInsertRow( ) not implemented" ); +} + +void SAL_CALL OResultSet::moveToCurrentRow( ) +{ + ResultSetEntryGuard aGuard( *this ); + SAL_INFO("connectivity.mork", "m_nRowPos = " << m_nRowPos); + if (rowInserted()) + { + m_nRowPos = 0; + fetchCurrentRow(); + } +} + +bool OResultSet::determineReadOnly() +{ +// OSL_FAIL( "OResultSet::determineReadOnly( ) not implemented" ); + + if (m_bIsReadOnly == TRISTATE_INDET) + { + m_bIsReadOnly = TRISTATE_TRUE; +// OConnection* xConnection = static_cast<OConnection*>(m_pStatement->getConnection().get()); +// m_bIsReadOnly = !m_aQueryHelper.isWritable(xConnection) || m_bIsAlwaysFalseQuery; + } + + return m_bIsReadOnly != TRISTATE_FALSE; +} + +void OResultSet::setTable(OTable* _rTable) +{ + m_xTable = _rTable; + m_xTableColumns = m_xTable->getColumns(); + if(m_xTableColumns.is()) + m_aColumnNames = m_xTableColumns->getElementNames(); +} + +void OResultSet::setOrderByColumns(const std::vector<sal_Int32>& _aColumnOrderBy) +{ + m_aOrderbyColumnNumber = _aColumnOrderBy; +} + +void OResultSet::setOrderByAscending(const std::vector<TAscendingOrder>& _aOrderbyAsc) +{ + m_aOrderbyAscending = _aOrderbyAsc; +} +Sequence< sal_Int32 > SAL_CALL OResultSet::deleteRows( const Sequence< Any >& /*rows*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XDeleteRows::deleteRows", *this ); + return Sequence< sal_Int32 >(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MResultSet.hxx b/connectivity/source/drivers/mork/MResultSet.hxx new file mode 100644 index 000000000..0531781d7 --- /dev/null +++ b/connectivity/source/drivers/mork/MResultSet.hxx @@ -0,0 +1,350 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MRESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MRESULTSET_HXX + +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <cppuhelper/compbase.hxx> +#include <comphelper/proparrhlp.hxx> +#include <tools/gen.hxx> +#include <rtl/ref.hxx> +#include "MStatement.hxx" +#include "MQueryHelper.hxx" +#include <connectivity/CommonTools.hxx> +#include <connectivity/FValue.hxx> +#include <connectivity/sqliterator.hxx> +#include <TSortIndex.hxx> + +namespace connectivity +{ + namespace mork + { + + /* + ** java_sql_ResultSet + */ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate, + css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, + css::sdbcx::XRowLocate, + css::sdbcx::XDeleteRows, + css::lang::XServiceInfo> OResultSet_BASE; + + + typedef sal_Int64 TVoidPtr; + typedef std::allocator< TVoidPtr > TVoidAlloc; + typedef std::vector<TVoidPtr> TVoidVector; + + class OResultSet : public cppu::BaseMutex, + public OResultSet_BASE, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<OResultSet> + { + protected: + OCommonStatement* m_pStatement; + css::uno::Reference< css::uno::XInterface> m_xStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData; + sal_uInt32 m_nRowPos; + bool m_bWasNull; + sal_Int32 m_nResultSetType; + sal_Int32 m_nFetchDirection; + + + std::shared_ptr< ::connectivity::OSQLParseTreeIterator > + m_pSQLIterator; + const connectivity::OSQLParseNode* m_pParseTree; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + + // you can't delete objects of this type + virtual ~OResultSet() override; + public: + DECLARE_SERVICE_INFO(); + + OResultSet(OCommonStatement* pStmt, const std::shared_ptr< ::connectivity::OSQLParseTreeIterator >& _pSQLIterator ); + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + + // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + // XRowLocate + virtual css::uno::Any SAL_CALL getBookmark( ) override; + virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override; + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override; + virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override; + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override; + virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override; + // XDeleteRows + virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override; + +protected: + //MQuery m_aQuery; + MQueryHelper m_aQueryHelper; + rtl::Reference<OTable> m_xTable; + sal_Int32 m_CurrentRowCount; + css::uno::Reference< css::container::XNameAccess > + m_xTableColumns; + + std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time + std::vector<sal_Int32> m_aOrderbyColumnNumber; + std::vector<TAscendingOrder> m_aOrderbyAscending; + css::uno::Sequence< OUString> m_aColumnNames; + OValueRow m_aRow; + OValueRow m_aParameterRow; + sal_Int32 m_nParamIndex; + bool m_bIsAlwaysFalseQuery; + ::rtl::Reference<OKeySet> m_pKeySet; + TriState m_bIsReadOnly; + void resetParameters() { m_nParamIndex = 0; } + + ::rtl::Reference<connectivity::OSQLColumns> m_xColumns; // this are the select columns + + void parseParameter( const OSQLParseNode* pNode, OUString& rMatchString ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void fillRowData(); + void analyseWhereClause( const OSQLParseNode* parseTree, + MQueryExpression &queryExpression); + + bool isCount() const; + + bool IsSorted() const { return !m_aOrderbyColumnNumber.empty(); } + + enum eRowPosition { + NEXT_POS, PRIOR_POS, FIRST_POS, LAST_POS, ABSOLUTE_POS, RELATIVE_POS + }; + + sal_uInt32 currentRowCount(); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + bool fetchRow(sal_Int32 rowIndex,bool bForceReload=false); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + bool fetchCurrentRow(); + bool validRow( sal_uInt32 nRow ); + bool seekRow( eRowPosition pos, sal_Int32 nOffset = 0 ); + sal_Int32 deletedCount(); + void fillKeySet(sal_Int32 nMaxCardNumber); //When we get new rows, fill the m_pKeySet items for them + sal_Int32 getRowForCardNumber(sal_Int32 nCardNum); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + const ORowSetValue& getValue(sal_Int32 rowIndex, sal_Int32 columnIndex); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void updateValue(sal_Int32 columnIndex,const ORowSetValue& x ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static void checkPendingUpdate(); + sal_Int32 getCurrentCardNumber(); + +public: + bool determineReadOnly(); + // MozAddressbook Specific methods + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void executeQuery(); + + void setTable(OTable* _rTable); + + void setParameterRow(const OValueRow& _rParaRow) + { m_aParameterRow = _rParaRow; } + + void setBindingRow(const OValueRow& _aRow) + { m_aRow = _aRow; } + + void setColumnMapping(const std::vector<sal_Int32>& _aColumnMapping); + + void setOrderByColumns(const std::vector<sal_Int32>& _aColumnOrderBy); + + void setOrderByAscending(const std::vector<TAscendingOrder>& _aOrderbyAsc); + + inline sal_Int32 mapColumn(sal_Int32 column); + + /// @throws css::sdbc::SQLException + void checkIndex(sal_Int32 columnIndex ); + + static void setBoundedColumns( + const OValueRow& _rRow, + const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns, + const css::uno::Reference< css::container::XIndexAccess>& _xNames, + bool _bSetColumnMapping, + const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData, + std::vector<sal_Int32>& _rColMapping); + + ::osl::Mutex& getMutex() { return m_aMutex; } + void methodEntry(); + + private: + void impl_ensureKeySet() + { + if ( !m_pKeySet.is() ) + m_pKeySet = new OKeySet(); + } + + protected: + using OPropertySetHelper::getFastPropertyValue; + }; + + inline sal_Int32 OResultSet::mapColumn(sal_Int32 column) + { + sal_Int32 map = column; + + OSL_ENSURE(column > 0, "OResultSet::mapColumn: invalid column index!"); + // the first column (index 0) is for convenience only. The + // first real select column is no 1. + if ((column > 0) && (column < static_cast<sal_Int32>(m_aColMapping.size()))) + map = m_aColMapping[column]; + + return map; + } + + class ResultSetEntryGuard : public ::osl::MutexGuard + { + public: + explicit ResultSetEntryGuard( OResultSet& _rRS ) : ::osl::MutexGuard( _rRS.getMutex() ) + { + _rRS.methodEntry(); + } + }; + + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MResultSetMetaData.cxx b/connectivity/source/drivers/mork/MResultSetMetaData.cxx new file mode 100644 index 000000000..e05eced22 --- /dev/null +++ b/connectivity/source/drivers/mork/MResultSetMetaData.cxx @@ -0,0 +1,192 @@ +/* -*- 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 <comphelper/extract.hxx> +#include <tools/diagnose_ex.h> +#include "MResultSetMetaData.hxx" +#include <com/sun/star/sdbc/DataType.hpp> + +using namespace connectivity::mork; +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 ::dbtools; +using namespace ::comphelper; + + +OResultSetMetaData::~OResultSetMetaData() +{ + m_xColumns = nullptr; +} + + +void OResultSetMetaData::checkColumnIndex(sal_Int32 column) +{ + if(column <= 0 || column > static_cast<sal_Int32>(m_xColumns->size())) + throwInvalidIndexException(*this); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + return getPrecision(column); +} + + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 /*column*/ ) +{ + return DataType::VARCHAR; // at the moment there exists only this type +} + + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount( ) +{ + return static_cast<sal_Int32>(m_xColumns->size()); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive( sal_Int32 /*column*/ ) +{ + return false; +} + + +OUString SAL_CALL OResultSetMetaData::getSchemaName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + + +OUString SAL_CALL OResultSetMetaData::getColumnName( sal_Int32 column ) +{ + checkColumnIndex(column); + + OUString sColumnName; + try + { + Reference< XPropertySet > xColumnProps( (*m_xColumns)[column-1], UNO_SET_THROW ); + OSL_VERIFY( xColumnProps->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sColumnName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.mork"); + } + return sColumnName; +} + +OUString SAL_CALL OResultSetMetaData::getTableName( sal_Int32 /*column*/ ) +{ + return m_aTableName; +} + +OUString SAL_CALL OResultSetMetaData::getCatalogName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + +OUString SAL_CALL OResultSetMetaData::getColumnTypeName( sal_Int32 column ) +{ + checkColumnIndex(column); + return getString((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))); +} + +OUString SAL_CALL OResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + return getColumnName(column); +} + +OUString SAL_CALL OResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isCurrency( sal_Int32 column ) +{ + checkColumnIndex(column); + return getBOOL((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement( sal_Int32 /*column*/ ) +{ + return false; +} + +sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 /*column*/ ) +{ + return false; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column ) +{ + checkColumnIndex(column); + return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column ) +{ + checkColumnIndex(column); + return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))); +} + + +sal_Int32 SAL_CALL OResultSetMetaData::isNullable( sal_Int32 column ) +{ + checkColumnIndex(column); + return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isSearchable( sal_Int32 /*column*/ ) +{ + if ( !m_pTable || !m_pTable->getConnection() ) + { + OSL_FAIL( "OResultSetMetaData::isSearchable: suspicious: called without table or connection!" ); + return false; + } + + return true; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isReadOnly( sal_Int32 column ) +{ + checkColumnIndex(column); + bool bReadOnly = (*m_xColumns)[column-1]->getPropertySetInfo()->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION)) && + ::cppu::any2bool((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION))); + + return m_bReadOnly || bReadOnly || OTable::isReadOnly(); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + return !isReadOnly(column); +} + +sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 column ) +{ + return !isReadOnly(column); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MResultSetMetaData.hxx b/connectivity/source/drivers/mork/MResultSetMetaData.hxx new file mode 100644 index 000000000..5362a4ac0 --- /dev/null +++ b/connectivity/source/drivers/mork/MResultSetMetaData.hxx @@ -0,0 +1,88 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MRESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MRESULTSETMETADATA_HXX + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> +#include "MTable.hxx" + +namespace connectivity +{ + namespace mork + { + + //************ Class: ResultSetMetaData + + typedef ::cppu::WeakImplHelper<css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE; + + class OResultSetMetaData : public OResultSetMetaData_BASE + { + OUString m_aTableName; + ::rtl::Reference<connectivity::OSQLColumns> m_xColumns; + OTable* m_pTable; + bool m_bReadOnly; + + protected: + virtual ~OResultSetMetaData() override; + public: + // a constructor that is needed to return the object: + // OResultSetMetaData(OConnection* _pConnection) : m_pConnection(_pConnection){} + OResultSetMetaData(const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns, + const OUString& _aTableName,OTable* _pTable,bool aReadOnly + ) + :m_aTableName(_aTableName) + ,m_xColumns(_rxColumns) + ,m_pTable(_pTable) + ,m_bReadOnly(aReadOnly) + {} + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex(sal_Int32 column); + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MRESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MStatement.cxx b/connectivity/source/drivers/mork/MStatement.cxx new file mode 100644 index 000000000..bd153afa6 --- /dev/null +++ b/connectivity/source/drivers/mork/MStatement.cxx @@ -0,0 +1,471 @@ +/* -*- 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 <tools/diagnose_ex.h> +#include <sal/log.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/processfactory.hxx> +#include <connectivity/dbexception.hxx> + +#include <algorithm> + +#include "MDriver.hxx" +#include "MStatement.hxx" +#include <sqlbison.hxx> +#include "MResultSet.hxx" + +#include <strings.hrc> + +static ::osl::Mutex m_ThreadMutex; + +using namespace ::comphelper; +using namespace connectivity::mork; +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::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + + +OStatement::OStatement( OConnection* _pConnection) : OCommonStatement( _pConnection) +{ +} + +OCommonStatement::OCommonStatement(OConnection* _pConnection ) + :OCommonStatement_IBASE(m_aMutex) + ,OPropertySetHelper(OCommonStatement_IBASE::rBHelper) + ,m_xDBMetaData (_pConnection->getMetaData()) + ,m_pTable(nullptr) + ,m_pConnection(_pConnection) + ,m_aParser( comphelper::getComponentContext(_pConnection->getDriver()->getFactory()) ) + ,m_pSQLIterator( std::make_shared<OSQLParseTreeIterator>( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser ) ) +{ +} + + +OCommonStatement::~OCommonStatement() +{ +} + + +void OCommonStatement::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + clearWarnings(); + clearCachedResultSet(); + + m_pConnection.clear(); + + m_pSQLIterator->dispose(); + m_pParseTree.reset(); + + OCommonStatement_IBASE::disposing(); +} + +Any SAL_CALL OCommonStatement::queryInterface( const Type & rType ) +{ + Any aRet = OCommonStatement_IBASE::queryInterface(rType); + if(!aRet.hasValue()) + aRet = OPropertySetHelper::queryInterface(rType); + return aRet; +} + +Sequence< Type > SAL_CALL OCommonStatement::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),OCommonStatement_IBASE::getTypes()); +} + +void SAL_CALL OCommonStatement::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + } + dispose(); +} + +OCommonStatement::StatementType OCommonStatement::parseSql( const OUString& sql , bool bAdjusted) +{ + OUString aErr; + + m_pParseTree = m_aParser.parseTree(aErr,sql); + + if(m_pParseTree) + { + m_pSQLIterator->setParseTree(m_pParseTree.get()); + m_pSQLIterator->traverseAll(); + const OSQLTables& rTabs = m_pSQLIterator->getTables(); + + if (rTabs.empty()) + { + getOwnConnection()->throwSQLException( STR_QUERY_AT_LEAST_ONE_TABLES, *this ); + } + + Reference<XIndexAccess> xNames; + switch(m_pSQLIterator->getStatementType()) + { + case OSQLStatementType::Select: + + // at this moment we support only one table per select statement + + OSL_ENSURE( !rTabs.empty(), "Need a Table"); + + m_pTable = static_cast< OTable* > (rTabs.begin()->second.get()); + m_xColNames = m_pTable->getColumns(); + xNames.set(m_xColNames,UNO_QUERY); + // set the binding of the resultrow + m_aRow = new OValueVector(xNames->getCount()); + (*m_aRow)[0].setBound(true); + std::for_each(m_aRow->begin()+1,m_aRow->end(),TSetBound(false)); + // create the column mapping + createColumnMapping(); + + analyseSQL(); + return eSelect; + + case OSQLStatementType::CreateTable: + return eCreateTable; + + default: + break; + } + } + else if(!bAdjusted) //Our sql parser does not support a statement like "create table foo" + // So we append ("E-mail" varchar) to the last of it to make it work + { + return parseSql(sql + "(""E-mail"" character)", true); + } + + getOwnConnection()->throwSQLException( STR_QUERY_TOO_COMPLEX, *this ); + OSL_FAIL( "OCommonStatement::parseSql: unreachable!" ); + return eSelect; + +} + +Reference< XResultSet > OCommonStatement::impl_executeCurrentQuery() +{ + clearCachedResultSet(); + + ::rtl::Reference pResult( new OResultSet( this, m_pSQLIterator ) ); + initializeResultSet( pResult.get() ); + + pResult->executeQuery(); + cacheResultSet( pResult ); // only cache if we survived the execution + + return pResult.get(); + +} + + +void OCommonStatement::initializeResultSet( OResultSet* _pResult ) +{ + ENSURE_OR_THROW( _pResult, "invalid result set" ); + + _pResult->setColumnMapping(m_aColMapping); + _pResult->setOrderByColumns(m_aOrderbyColumnNumber); + _pResult->setOrderByAscending(m_aOrderbyAscending); + _pResult->setBindingRow(m_aRow); + _pResult->setTable(m_pTable); +} + + +void OCommonStatement::clearCachedResultSet() +{ + Reference< XResultSet > xResultSet( m_xResultSet.get(), UNO_QUERY ); + if ( !xResultSet.is() ) + return; + + Reference< XCloseable >( xResultSet, UNO_QUERY_THROW )->close(); + + m_xResultSet.clear(); +} + + +void OCommonStatement::cacheResultSet( const ::rtl::Reference< OResultSet >& _pResult ) +{ + ENSURE_OR_THROW( _pResult.is(), "invalid result set" ); + m_xResultSet = Reference< XResultSet >( _pResult.get() ); +} + + +sal_Bool SAL_CALL OCommonStatement::execute( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + Reference< XResultSet > xRS = executeQuery( sql ); + // returns true when a resultset is available + return xRS.is(); +} + + +Reference< XResultSet > SAL_CALL OCommonStatement::executeQuery( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_ThreadMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + // parse the statement + StatementType eStatementType = parseSql( sql ); + if ( eStatementType != eSelect ) + return nullptr; + + return impl_executeCurrentQuery(); +} + + +Reference< XConnection > SAL_CALL OCommonStatement::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + // just return our connection here + return Reference< XConnection >(m_pConnection.get()); +} + +Any SAL_CALL OStatement::queryInterface( const Type & rType ) +{ + Any aRet = ::cppu::queryInterface(rType,static_cast< XServiceInfo*> (this)); + if(!aRet.hasValue()) + aRet = OCommonStatement::queryInterface(rType); + return aRet; +} + +sal_Int32 SAL_CALL OCommonStatement::executeUpdate( const OUString& /*sql*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XStatement::executeUpdate", *this ); + return 0; + +} + +Any SAL_CALL OCommonStatement::getWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + return makeAny(m_aLastWarning); +} + + +void SAL_CALL OCommonStatement::clearWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OCommonStatement_IBASE::rBHelper.bDisposed); + + + m_aLastWarning = SQLWarning(); +} + +::cppu::IPropertyArrayHelper* OCommonStatement::createArrayHelper( ) const +{ + // this properties are define by the service resultset + // they must in alphabetic order + Sequence< Property > aProps(9); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + + +::cppu::IPropertyArrayHelper & OCommonStatement::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool OCommonStatement::convertFastPropertyValue( + Any & /*rConvertedValue*/, + Any & /*rOldValue*/, + sal_Int32 /*nHandle*/, + const Any& /*rValue*/ ) +{ + // here we have to try to convert + return false; +} + +void OCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& /*rValue*/) +{ + // set the value to whatever is necessary + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + default: + ; + } +} + +void OCommonStatement::getFastPropertyValue(Any& /*rValue*/,sal_Int32 nHandle) const +{ + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + default: + ; + } +} + +IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.OStatement","com.sun.star.sdbc.Statement"); + +void SAL_CALL OCommonStatement::acquire() throw() +{ + OCommonStatement_IBASE::acquire(); +} + +void SAL_CALL OCommonStatement::release() throw() +{ + OCommonStatement_IBASE::release(); +} + +void SAL_CALL OStatement::acquire() throw() +{ + OCommonStatement::acquire(); +} + +void SAL_CALL OStatement::release() throw() +{ + OCommonStatement::release(); +} + +Reference< css::beans::XPropertySetInfo > SAL_CALL OCommonStatement::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +void OCommonStatement::createColumnMapping() +{ + size_t i; + + // initialize the column index map (mapping select columns to table columns) + ::rtl::Reference<connectivity::OSQLColumns> xColumns = m_pSQLIterator->getSelectColumns(); + m_aColMapping.resize(xColumns->size() + 1); + for (i=0; i<m_aColMapping.size(); ++i) + m_aColMapping[i] = static_cast<sal_Int32>(i); + + Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY); + // now check which columns are bound +#if OSL_DEBUG_LEVEL > 0 + for ( i = 0; i < m_aColMapping.size(); i++ ) + SAL_INFO( + "connectivity.mork", + "BEFORE Mapped: " << i << " -> " << m_aColMapping[i]); +#endif + OResultSet::setBoundedColumns(m_aRow,xColumns,xNames,true,m_xDBMetaData,m_aColMapping); +#if OSL_DEBUG_LEVEL > 0 + for ( i = 0; i < m_aColMapping.size(); i++ ) + SAL_INFO( + "connectivity.mork", + "AFTER Mapped: " << i << " -> " << m_aColMapping[i]); +#endif +} + + +void OCommonStatement::analyseSQL() +{ + const OSQLParseNode* pOrderbyClause = m_pSQLIterator->getOrderTree(); + if(!pOrderbyClause) + return; + + OSQLParseNode * pOrderingSpecCommalist = pOrderbyClause->getChild(2); + OSL_ENSURE(SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OResultSet: Error in Parse Tree"); + + for (size_t m = 0; m < pOrderingSpecCommalist->count(); m++) + { + OSQLParseNode * pOrderingSpec = pOrderingSpecCommalist->getChild(m); + OSL_ENSURE(SQL_ISRULE(pOrderingSpec,ordering_spec),"OResultSet: Error in Parse Tree"); + OSL_ENSURE(pOrderingSpec->count() == 2,"OResultSet: Error in Parse Tree"); + + OSQLParseNode * pColumnRef = pOrderingSpec->getChild(0); + if(!SQL_ISRULE(pColumnRef,column_ref)) + { + throw SQLException(); + } + OSQLParseNode * pAscendingDescending = pOrderingSpec->getChild(1); + setOrderbyColumn(pColumnRef,pAscendingDescending); + } +} + +void OCommonStatement::setOrderbyColumn(OSQLParseNode const * pColumnRef, + OSQLParseNode const * pAscendingDescending) +{ + OUString aColumnName; + if (pColumnRef->count() == 1) + aColumnName = pColumnRef->getChild(0)->getTokenValue(); + else if (pColumnRef->count() == 3) + { + pColumnRef->getChild(2)->parseNodeToStr( aColumnName, getOwnConnection(), nullptr, false, false ); + } + else + { + throw SQLException(); + } + + Reference<XColumnLocate> xColLocate(m_xColNames,UNO_QUERY); + if(!xColLocate.is()) + return; + + m_aOrderbyColumnNumber.push_back(xColLocate->findColumn(aColumnName)); + + // Ascending or Descending? + m_aOrderbyAscending.push_back(SQL_ISTOKEN(pAscendingDescending,DESC) ? TAscendingOrder::DESC : TAscendingOrder::ASC); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MStatement.hxx b/connectivity/source/drivers/mork/MStatement.hxx new file mode 100644 index 000000000..3cd7113a8 --- /dev/null +++ b/connectivity/source/drivers/mork/MStatement.hxx @@ -0,0 +1,184 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MSTATEMENT_HXX + +#include <comphelper/proparrhlp.hxx> +#include <connectivity/sqliterator.hxx> +#include <connectivity/sqlparse.hxx> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <TSortIndex.hxx> +#include "MTable.hxx" + +#include <memory> + +namespace connectivity +{ + namespace mork + { + class OResultSet; + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement, + css::sdbc::XWarningsSupplier, + css::sdbc::XCloseable> OCommonStatement_IBASE; + + + //************ Class: OCommonStatement + // is a base class for the normal statement and for the prepared statement + + class OCommonStatement; + + class OCommonStatement :public cppu::BaseMutex + ,public OCommonStatement_IBASE + ,public ::cppu::OPropertySetHelper + ,public ::comphelper::OPropertyArrayUsageHelper< OCommonStatement > + { + private: + css::sdbc::SQLWarning m_aLastWarning; + + protected: + css::uno::WeakReference< css::sdbc::XResultSet > m_xResultSet; + css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xDBMetaData; + css::uno::Reference< css::container::XNameAccess> m_xColNames; // table columns + + // for this Statement + + OTable* m_pTable; + rtl::Reference<OConnection> m_pConnection; // The owning Connection object + + OValueRow m_aRow; + + connectivity::OSQLParser m_aParser; + std::shared_ptr< ::connectivity::OSQLParseTreeIterator > + m_pSQLIterator; + + std::unique_ptr<connectivity::OSQLParseNode> m_pParseTree; + + std::vector<sal_Int32> m_aColMapping; + std::vector<sal_Int32> m_aOrderbyColumnNumber; + std::vector<TAscendingOrder> m_aOrderbyAscending; + + protected: + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle) const override; + virtual ~OCommonStatement() override; + + protected: + + // Driver Internal Methods + + enum StatementType { eSelect, eCreateTable }; + /** called to do the parsing of a to-be-executed SQL statement, and set all members as needed + + @throws css::sdbc::SQLException + @throws css::uno::RuntimeException + */ + virtual StatementType + parseSql( const OUString& sql , bool bAdjusted = false); + /** called to initialize a result set, according to a previously parsed SQL statement + */ + virtual void initializeResultSet( OResultSet* _pResult ); + /** called when a possible cached instance of our last result set should be cleared + */ + virtual void clearCachedResultSet(); + /** caches a result set which has just been created by an execution of an SQL statement + */ + virtual void cacheResultSet( const ::rtl::Reference< OResultSet >& _pResult ); + + + /** executes the current query (the one which has been passed to the last parseSql call) + */ + css::uno::Reference< css::sdbc::XResultSet > + impl_executeCurrentQuery(); + + void createColumnMapping(); + void analyseSQL(); + void setOrderbyColumn( connectivity::OSQLParseNode const * pColumnRef, + connectivity::OSQLParseNode const * pAscendingDescending); + + public: + // other methods + OConnection* getOwnConnection() const { return m_pConnection.get(); } + + explicit OCommonStatement(OConnection* _pConnection ); + using OCommonStatement_IBASE::operator css::uno::Reference< css::uno::XInterface >; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XInterface + virtual void SAL_CALL release() throw() override; + virtual void SAL_CALL acquire() throw() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ; + virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ; + virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + + protected: + using OPropertySetHelper::getFastPropertyValue; + }; + + class OStatement : public OCommonStatement, + public css::lang::XServiceInfo + { + protected: + virtual ~OStatement() override {} + public: + // a constructor, for when the object needs to be returned: + explicit OStatement( OConnection* _pConnection); + DECLARE_SERVICE_INFO(); + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MTable.cxx b/connectivity/source/drivers/mork/MTable.cxx new file mode 100644 index 000000000..76db19fc6 --- /dev/null +++ b/connectivity/source/drivers/mork/MTable.cxx @@ -0,0 +1,57 @@ +/* -*- 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 "MTable.hxx" +#include "MColumns.hxx" +#include <connectivity/TKeys.hxx> +#include <connectivity/TIndexes.hxx> + + +using namespace connectivity::mork; +using namespace connectivity; + + +OTable::OTable( sdbcx::OCollection* _pTables, OConnection* _pConnection, + const OUString& Name, const OUString& Type, const OUString& Description ) + :OTable_Base(_pTables, _pConnection, true, Name, Type, Description ) + ,m_pConnection( _pConnection ) +{ + construct(); +} + + +sdbcx::OCollection* OTable::createColumns( const ::std::vector< OUString>& _rNames ) +{ + return new OColumns( this, m_aMutex, _rNames ); +} + + +sdbcx::OCollection* OTable::createKeys(const ::std::vector< OUString>& _rNames) +{ + return new OKeysHelper( this, m_aMutex, _rNames ); +} + + +sdbcx::OCollection* OTable::createIndexes(const ::std::vector< OUString>& _rNames) +{ + return new OIndexesHelper( this, m_aMutex, _rNames ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MTable.hxx b/connectivity/source/drivers/mork/MTable.hxx new file mode 100644 index 000000000..7cbe216be --- /dev/null +++ b/connectivity/source/drivers/mork/MTable.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MTABLE_HXX + +#include <connectivity/TTableHelper.hxx> +#include "MConnection.hxx" + +namespace connectivity +{ + namespace mork + { + typedef ::connectivity::OTableHelper OTable_Base; + + class OTable : public OTable_Base + { + OConnection* m_pConnection; + + public: + OTable( sdbcx::OCollection* _pTables, + OConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description ); + + OConnection* getConnection() { return m_pConnection;} + + static bool isReadOnly() { return false; } + + const OUString& getTableName() const { return m_Name; } + const OUString& getSchema() const { return m_SchemaName; } + + // OTableHelper overridables + virtual sdbcx::OCollection* createColumns( const ::std::vector< OUString>& _rNames ) override; + virtual sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override; + virtual sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override; + private: + using OTable_Base::getConnection; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MTables.cxx b/connectivity/source/drivers/mork/MTables.cxx new file mode 100644 index 000000000..f1f169e2a --- /dev/null +++ b/connectivity/source/drivers/mork/MTables.cxx @@ -0,0 +1,70 @@ +/* -*- 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 "MTables.hxx" +#include "MTable.hxx" +#include "MCatalog.hxx" +#include <comphelper/types.hxx> + +#include <com/sun/star/sdbc/XRow.hpp> + +using namespace connectivity; +using namespace connectivity::mork; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; + +sdbcx::ObjectType OTables::createObject(const OUString& _rName) +{ + OUString aName,aSchema; + aSchema = "%"; + aName = _rName; + + Sequence< OUString > aTypes { "%" }; + + Reference< XResultSet > xResult = m_xMetaData->getTables(Any(),aSchema,aName,aTypes); + + sdbcx::ObjectType xRet; + if(xResult.is()) + { + Reference< XRow > xRow(xResult,UNO_QUERY); + if(xResult->next()) // there can be only one table with this name + { + OTable* pRet = new OTable( this, static_cast<OCatalog&>(m_rParent).getConnection(), + aName,xRow->getString(4),xRow->getString(5)); + xRet = pRet; + } + } + ::comphelper::disposeComponent(xResult); + + return xRet; +} + +void OTables::impl_refresh( ) +{ + static_cast<OCatalog&>(m_rParent).refreshTables(); +} + +void OTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MTables.hxx b/connectivity/source/drivers/mork/MTables.hxx new file mode 100644 index 000000000..ac3730f9a --- /dev/null +++ b/connectivity/source/drivers/mork/MTables.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MTABLES_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +namespace connectivity +{ + namespace mork + { + class OTables : public sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + public: + OTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + ,m_xMetaData(_rMetaData) + {} + + // only the name is identical to ::cppu::OComponentHelper + virtual void disposing() override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MTABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MorkParser.cxx b/connectivity/source/drivers/mork/MorkParser.cxx new file mode 100644 index 000000000..188f8e6fb --- /dev/null +++ b/connectivity/source/drivers/mork/MorkParser.cxx @@ -0,0 +1,757 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2006, ScalingWeb.com + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * * Neither the name of ScalingWeb.com nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior + * written permission of ScalingWeb.com. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "MorkParser.hxx" +#include <boost/io/ios_state.hpp> +#include <stdlib.h> +#include <string> +#include <string.h> +#include <fstream> +#include <iostream> + +std::string const g_Empty = ""; + +const char * const MorkDictColumnMeta = "<(a=c)>"; + +static const int defaultScope_ = 0x80; + +MorkParser::MorkParser() : + columns_(), + values_(), + mork_(), + currentCells_(nullptr), + error_(NoError), + morkData_(), + morkPos_(0), + nextAddValueId_(0x7fffffff), + defaultTableId_(1), + nowParsing_(NP::Values) +{ +} + +bool MorkParser::open( const std::string &path ) +{ + initVars(); + std::string line; + std::ifstream infile(path.c_str(), std::ios_base::in); + if(!infile.is_open()) + { + error_ = FailedToOpen; + return false; + } + + while (getline(infile, line, '\n')) + { + morkData_.append(line); + morkData_.append("\n"); + } + + // Parse mork + return parse(); +} + +void MorkParser::initVars() +{ + error_ = NoError; + morkPos_ = 0; + nowParsing_ = NP::Values; + currentCells_ = nullptr; + nextAddValueId_ = 0x7fffffff; +} + +bool MorkParser::parse() +{ + bool Result = true; + + // Run over mork chars and parse each term + char cur = nextChar(); + + while ( Result && cur ) + { + if ( !isWhiteSpace( cur ) ) + { + // Figure out what a term + switch ( cur ) + { + case '<': + // Dict + Result = parseDict(); + break; + case '/': + // Comment + Result = parseComment(); + break; + case '{': + Result = parseTable(); + // Table + break; + case '[': + Result = parseRow( 0, 0 ); + // Row + break; + case '@': + parseGroup(); + // Group + break; + default: + error_ = DefectedFormat; + Result = false; + break; + } + } + + // Get next char + cur = nextChar(); + } + + return Result; +} + +bool MorkParser::isWhiteSpace( char c ) +{ + switch ( c ) + { + case ' ': + case '\t': + case '\r': + case '\n': + case '\f': + return true; + default: + return false; + } +} + +inline char MorkParser::nextChar() +{ + char cur = 0; + + + if ( morkPos_ < morkData_.length() ) + { + cur = morkData_[ morkPos_ ]; + morkPos_++; + } + + if ( !cur ) + { + cur = 0; + } + + return cur; +} + +bool MorkParser::parseDict() +{ + char cur = nextChar(); + bool Result = true; + nowParsing_ = NP::Values; + + while ( Result && cur != '>' && cur ) + { + if ( !isWhiteSpace( cur ) ) + { + switch ( cur ) + { + case '<': + { + + if ( morkData_.substr( morkPos_ - 1, strlen( MorkDictColumnMeta ) ) == MorkDictColumnMeta ) + { + nowParsing_ = NP::Columns; + morkPos_ += strlen( MorkDictColumnMeta ) - 1; + } + + + break; + } + case '(': + Result = parseCell(); + break; + case '/': + Result = parseComment(); + break; + + } + } + + cur = nextChar(); + } + + return Result; +} + +inline bool MorkParser::parseComment() +{ + char cur = nextChar(); + if ( '/' != cur ) return false; + + while ( cur != '\r' && cur != '\n' && cur ) + { + cur = nextChar(); + } + + return true; +} + +bool MorkParser::parseCell() +{ + bool Result = true; + bool bValueOid = false; + bool bColumn = true; + int Corners = 0; + + // Column = Value + std::string Column; + std::string Text; + Column.reserve( 4 ); + Text.reserve( 32 ); + + char cur = nextChar(); + + // Process cell start with column (bColumn == true) + while ( Result && cur != ')' && cur ) + { + switch ( cur ) + { + case '^': + // Oids + Corners++; + if ( 1 == Corners ) + { + } + else if ( 2 == Corners ) + { + bColumn = false; + bValueOid = true; + } + else + { + Text += cur; + } + + break; + case '=': + // From column to value + if ( bColumn ) + { + bColumn = false; + } + else + { + Text += cur; + } + break; + case '\\': + { + // Get next two chars + char NextChar= nextChar(); + if ( '\r' != NextChar && '\n' != NextChar ) + { + Text += NextChar; + } + else + { + (void)nextChar(); + } + } + break; + case '$': + { + // Get next two chars + std::string HexChar; + HexChar += nextChar(); + HexChar += nextChar(); + Text += static_cast<char>(strtoul(HexChar.c_str(), nullptr, 16)); + } + break; + default: + // Just a char + if ( bColumn ) + { + Column += cur; + } + else + { + Text += cur; + } + break; + } + + cur = nextChar(); + } + + // Apply column and text + int ColumnId = strtoul(Column.c_str(), nullptr, 16); + + if ( NP::Rows != nowParsing_ ) + { + // Dicts + if ( !Text.empty() ) + { + if ( nowParsing_ == NP::Columns ) + { + columns_[ ColumnId ] = Text; + } + else + { + values_[ ColumnId ] = Text; + } + } + } + else + { + if ( !Text.empty() ) + { + // Rows + //int ValueId = string( Text.c_str() ).toInt( 0, 16 ); + int ValueId = strtoul(Text.c_str(), nullptr, 16); + + if ( bValueOid ) + { + ( *currentCells_ )[ ColumnId ] = ValueId; + } + else + { + nextAddValueId_--; + values_[ nextAddValueId_ ] = Text; + ( *currentCells_ )[ ColumnId ] = nextAddValueId_; + } + } + } + + return Result; +} + +bool MorkParser::parseTable() +{ + bool Result = true; + std::string TextId; + int Id = 0, Scope = 0; + + char cur = nextChar(); + + // Get id + while ( cur != '{' && cur != '[' && cur != '}' && cur ) + { + if ( !isWhiteSpace( cur ) ) + { + TextId += cur; + } + + cur = nextChar(); + } + + parseScopeId( TextId, &Id, &Scope ); + + // Parse the table + while ( Result && cur != '}' && cur ) + { + if ( !isWhiteSpace( cur ) ) + { + switch ( cur ) + { + case '{': + parseMeta( '}' ); + break; + case '[': + Result = parseRow( Id, Scope ); + break; + case '-': + case '+': + break; + default: + { + std::string JustId; + while ( !isWhiteSpace( cur ) && cur ) + { + JustId += cur; + cur = nextChar(); + + if ( cur == '}' ) + { + return Result; + } + } + + int JustIdNum = 0, JustScopeNum = 0; + parseScopeId( JustId, &JustIdNum, &JustScopeNum ); + + setCurrentRow( Scope, Id, JustScopeNum, JustIdNum ); + } + break; + } + } + + cur = nextChar(); + } + + return Result; +} + +void MorkParser::parseScopeId( const std::string &TextId, int *Id, int *Scope ) +{ + int Pos = 0; + + if ( ( Pos = TextId.find( ':' ) ) >= 0 ) + { + std::string tId = TextId.substr( 0, Pos ); + std::string tSc = TextId.substr( Pos + 1, TextId.length() - Pos ); + + if ( tSc.length() > 1 && '^' == tSc[ 0 ] ) + { + // Delete '^' + tSc.erase( 0, 1 ); + } + + *Id = strtoul(tId.c_str(), nullptr, 16); + + *Scope = strtoul(tSc.c_str(), nullptr, 16); + } + else + { + *Id = strtoul(TextId.c_str(), nullptr, 16); + } +} + +inline void MorkParser::setCurrentRow( int TableScope, int TableId, int RowScope, int RowId ) +{ + if ( !RowScope ) + { + RowScope = defaultScope_; + } + + if ( !TableScope ) + { + TableScope = defaultScope_; + } + + // 01.08.2012 davido + // TableId 0 is wrong here. + // Straying rows (rows that defined outside the table) belong to the default scope and table is the last was seen: 1:^80 + // (at least i read so the specification) + if (TableId) + { + defaultTableId_ = TableId; + } + + if (!TableId) + { + TableId = defaultTableId_; + } + + currentCells_ = &( mork_.map[ abs( TableScope ) ].map[ abs( TableId ) ].map[ abs( RowScope ) ].map[ abs( RowId ) ] ); +} + +bool MorkParser::parseRow( int TableId, int TableScope ) +{ + bool Result = true; + std::string TextId; + int Id = 0, Scope = 0; + nowParsing_ = NP::Rows; + + char cur = nextChar(); + + // Get id + while ( cur != '(' && cur != ']' && cur != '[' && cur ) + { + if ( !isWhiteSpace( cur ) ) + { + TextId += cur; + } + + cur = nextChar(); + } + + parseScopeId( TextId, &Id, &Scope ); + setCurrentRow( TableScope, TableId, Scope, Id ); + + // Parse the row + while ( Result && cur != ']' && cur ) + { + if ( !isWhiteSpace( cur ) ) + { + switch ( cur ) + { + case '(': + Result = parseCell(); + break; + case '[': + parseMeta( ']' ); + break; + default: + Result = false; + break; + } + } + + cur = nextChar(); + } + + return Result; +} + +void MorkParser::parseGroup() +{ + parseMeta( '@' ); +} + +void MorkParser::parseMeta( char c ) +{ + char cur = nextChar(); + + while ( cur != c && cur ) + { + cur = nextChar(); + } +} + +MorkTableMap *MorkParser::getTables( int TableScope ) +{ + TableScopeMap::Map::iterator iter = mork_.map.find( TableScope ); + + if ( iter == mork_.map.end() ) + { + return nullptr; + } + + return &iter->second; +} + +MorkRowMap *MorkParser::getRows( int RowScope, RowScopeMap *table ) +{ + RowScopeMap::Map::iterator iter = table->map.find( RowScope ); + + if ( iter == table->map.end() ) + { + return nullptr; + } + + return &iter->second; +} + +std::string const &MorkParser::getValue( int oid ) +{ + MorkDict::iterator foundIter = values_.find( oid ); + + if ( values_.end() == foundIter ) + { + return g_Empty; + } + + return foundIter->second; +} + +std::string const &MorkParser::getColumn( int oid ) +{ + MorkDict::iterator foundIter = columns_.find( oid ); + + if ( columns_.end() == foundIter ) + { + return g_Empty; + } + + return foundIter->second; +} + +void MorkParser::retrieveLists(std::set<std::string>& lists) +{ +#ifdef VERBOSE + boost::io::ios_all_saver ias(std::cout); + std::cout << std::hex << std::uppercase; +#endif + + MorkTableMap* tables = getTables(defaultScope_); + if (!tables) return; + for (auto& rTable : tables->map) + { +#ifdef VERBOSE + std::cout << "\t Table:" + << ( ( int ) rTable.first < 0 ? "-" : " " ) + << rTable.first << std::endl; +#endif + MorkRowMap* rows = getRows( 0x81/*defaultListScope*/, &rTable.second ); + if (!rows) return; + for ( const auto& rRow : rows->map ) + { +#ifdef VERBOSE + std::cout << "\t\t\t Row Id:" + << ( ( int ) rRow.first < 0 ? "-" : " ") + << rRow.first << std::endl; + std::cout << "\t\t\t\t Cells:\r\n"; +#endif + // Get cells + MorkCells::const_iterator cellsIter = rRow.second.find(0xC1); + if (cellsIter != rRow.second.end()) + lists.insert(getValue( cellsIter->second )); + } + } +} + +void MorkParser::getRecordKeysForListTable(std::string const & listName, std::set<int>& records) +{ +#ifdef VERBOSE + boost::io::ios_all_saver ias(std::cout); + std::cout << std::hex << std::uppercase; +#endif + + MorkTableMap* tables = getTables(defaultScope_); + if (!tables) return; + for (auto& rTable : tables->map) + { +#ifdef VERBOSE + std::cout << "\t Table:" + << ( ( int ) rTable.first < 0 ? "-" : " " ) + << rTable.first << std::endl; +#endif + MorkRowMap* rows = getRows( 0x81, &rTable.second ); + if (!rows) return; + for ( const auto& rRow : rows->map ) + { +#ifdef VERBOSE + std::cout << "\t\t\t Row Id:" + << ( ( int ) rRow.first < 0 ? "-" : " ") + << rRow.first << std::endl; + std::cout << "\t\t\t\t Cells:\r\n"; +#endif + // Get cells + bool isListFound = false; + for ( const auto& [rColumnId, rValueId] : rRow.second ) + { + if (isListFound) + { + if (rColumnId >= 0xC7) + { + std::string value = getValue(rValueId); + int id = strtoul(value.c_str(), nullptr, 16); + records.insert(id); + } + } + else if ((rColumnId == 0xC1) && + listName == getValue( rValueId )) + { + isListFound = true; + } + } + + } + } +} + +void MorkParser::dump() +{ + boost::io::ios_all_saver ias(std::cout); + std::cout << std::hex << std::uppercase; + + std::cout << "Column Dict:\r\n"; + std::cout << "=============================================\r\n\r\n"; + + //// columns dict + for ( const auto& [rColumnId, rText] : columns_ ) + { + std::cout << rColumnId + << " : " + << rText + << std::endl; + } + + //// values dict + std::cout << "\r\nValues Dict:\r\n"; + std::cout << "=============================================\r\n\r\n"; + + for ( const auto& [rValueId, rText] : values_ ) + { + if (rValueId >= nextAddValueId_) { + continue; + } + + std::cout << rValueId + << " : " + << rText + << "\r\n"; + } + + std::cout << std::endl << "Data:" << std::endl; + std::cout << "=============================================" + << std::endl << std::endl; + + //// Mork data + for ( const auto& [rTableScopeId, rTableScope] : mork_.map ) + { + std::cout << "\r\n Scope:" << rTableScopeId << std::endl; + + for ( const auto& [rTableId, rTable] : rTableScope.map ) + { + std::cout << "\t Table:" + << ( rTableId < 0 ? "-" : " " ) + << rTableId << std::endl; + + for (const auto& [rRowScopeId, rRowScope] : rTable.map) + { + std::cout << "\t\t RowScope:" + << rRowScopeId << std::endl; + + for (const auto& [rRowId, rRow] : rRowScope.map) + { + std::cout << "\t\t\t Row Id:" + << (rRowId < 0 ? "-" : " ") + << rRowId << std::endl; + std::cout << "\t\t\t\t Cells:" << std::endl; + + for (const auto& [rColumnId, rValueId] : rRow) + { + // Write ids + std::cout << "\t\t\t\t\t" + << rColumnId + << " : " + << rValueId + << " => "; + + MorkDict::const_iterator FoundIter = values_.find( rValueId ); + if ( FoundIter != values_.end() ) + { + // Write string values + std::cout << columns_[ rColumnId ].c_str() + << " : " + << FoundIter->second.c_str() + << std::endl; + } + } + } + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/MorkParser.hxx b/connectivity/source/drivers/mork/MorkParser.hxx new file mode 100644 index 000000000..d16fc417d --- /dev/null +++ b/connectivity/source/drivers/mork/MorkParser.hxx @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2006, ScalingWeb.com + * All rights reserved. + * + * Redistribution and use of this software in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * * Neither the name of ScalingWeb.com nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior + * written permission of ScalingWeb.com. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MORKPARSER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_MORKPARSER_HXX + +#include <rtl/ustring.hxx> + +#include <string> +#include <map> +#include <set> +#include <vector> + +#include "dllapi.h" + +// Types + +typedef std::map< int, std::string > MorkDict; +typedef std::map< int, int > MorkCells; // ColumnId : ValueId +struct MorkRowMap { typedef std::map< int, MorkCells > Map; Map map; }; // Row id +struct RowScopeMap { typedef std::map< int, MorkRowMap > Map; Map map; }; // Row scope +struct MorkTableMap { typedef std::map< int, RowScopeMap > Map; Map map; }; // Table id +struct TableScopeMap { typedef std::map< int, MorkTableMap > Map; Map map; }; // Table Scope + +// Error codes +enum MorkErrors +{ + NoError = 0, + FailedToOpen, + DefectedFormat +}; + + +/// Class MorkParser + +class LO_DLLPUBLIC_MORK MorkParser final +{ +public: + + explicit MorkParser(); + + /// Open and parse mork file + + bool open( const std::string &path ); + + /// Returns all tables of specified scope + + MorkTableMap *getTables( int tableScope ); + + /// Returns all rows under specified scope + + static MorkRowMap *getRows( int rowScope, RowScopeMap *table ); + + /// Return value of specified value oid + + std::string const &getValue( int oid ); + + /// Return value of specified column oid + + std::string const &getColumn( int oid ); + + void retrieveLists(std::set<std::string>& lists); + void getRecordKeysForListTable(std::string const & listName, std::set<int>& records); + + void dump(); + + // All lists + std::vector<OUString> lists_; + +private: // Members + + void initVars(); + + static bool isWhiteSpace( char c ); + char nextChar(); + + static void parseScopeId( const std::string &TextId, int *Id, int *Scope ); + void setCurrentRow( int TableScope, int TableId, int RowScope, int RowId ); + + // Parse methods + bool parse(); + bool parseDict(); + bool parseComment(); + bool parseCell(); + bool parseTable(); + void parseMeta( char c ); + bool parseRow( int TableId, int TableScope ); + void parseGroup(); + +private: // Data + + // Columns in mork means value names + MorkDict columns_; + MorkDict values_; + + // All mork file data + TableScopeMap mork_; + MorkCells *currentCells_; + + // Error status of last operation + MorkErrors error_; + + // All Mork data + std::string morkData_; + + + unsigned morkPos_; + int nextAddValueId_; + int defaultTableId_; + + // Indicates entity is being parsed + enum class NP { Columns, Values, Rows } nowParsing_; + + MorkParser(const MorkParser &) = delete; + MorkParser &operator=(const MorkParser &) = delete; + +}; + +#endif // __MorkParser_h__ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/README b/connectivity/source/drivers/mork/README new file mode 100644 index 000000000..0d4207b0c --- /dev/null +++ b/connectivity/source/drivers/mork/README @@ -0,0 +1,41 @@ +Mork Format Parsing Library +============================= + +Description +----------- + +Cross Platform Mozilla Mork format reader. + + +Compilation +------------ + +g++ -o MorkParser main.cpp MorkParser.cpp + + +License +------- + +This program is licensed under permissive BSD license. +See the license.txt file for more information. + + +Date: October 16th, 2007 + +Project Maintainers: + Yuriy Soroka + ysoroka@scalingweb.com + + http://www.scalingweb.com/ + +Thanks +------------- +Thanks to Petr Stejskal <stejsky@volny.cz> who helped with porting this code from Qt to STL. + + +How you can help +---------------- + + Comments, patches, bug reports are welcome. + + diff --git a/connectivity/source/drivers/mork/dllapi.h b/connectivity/source/drivers/mork/dllapi.h new file mode 100644 index 000000000..adf269107 --- /dev/null +++ b/connectivity/source/drivers/mork/dllapi.h @@ -0,0 +1,25 @@ + +/* -*- 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/. + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_DLLAPI_H +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MORK_DLLAPI_H + +#include <sal/config.h> +#include <sal/types.h> + +#if defined LO_DLLIMPLEMENTATION_MORK +#define LO_DLLPUBLIC_MORK SAL_DLLPUBLIC_EXPORT +#else +#define LO_DLLPUBLIC_MORK SAL_DLLPUBLIC_IMPORT +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mork/license.txt b/connectivity/source/drivers/mork/license.txt new file mode 100644 index 000000000..3e41befc7 --- /dev/null +++ b/connectivity/source/drivers/mork/license.txt @@ -0,0 +1,31 @@ +Software License Agreement (BSD License) + +Copyright (c) 2006, ScalingWeb.com +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of ScalingWeb.com nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of ScalingWeb.com. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/connectivity/source/drivers/mork/mork.component b/connectivity/source/drivers/mork/mork.component new file mode 100644 index 000000000..1eeb6affb --- /dev/null +++ b/connectivity/source/drivers/mork/mork.component @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.MorkDriver" + constructor="com_sun_star_comp_sdbc_MorkDriver_get_implementation"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/mork/mork_helper.cxx b/connectivity/source/drivers/mork/mork_helper.cxx new file mode 100644 index 000000000..4cb11864f --- /dev/null +++ b/connectivity/source/drivers/mork/mork_helper.cxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#include "MorkParser.hxx" +#include <iostream> +#include <sal/log.hxx> + +static bool openAddressBook(const std::string& path) +{ + MorkParser mork; + // Open and parse mork file + if (!mork.open(path)) + { + return false; + } + + const int defaultScope = 0x80; + MorkTableMap *Tables = mork.getTables( defaultScope ); + if ( Tables ) + { + // Iterate all tables + for (auto const& table : Tables->map) + { + if ( 0 == table.first ) continue; + SAL_INFO("connectivity.mork", "table->first : " << table.first); + std::string column = mork.getColumn( table.first ); + std::string value = mork.getValue( table.first ); + SAL_INFO("connectivity.mork", "table.column : " << column); + SAL_INFO("connectivity.mork", "table.value : " << value); + } + } + + mork.dump(); + + return true; +} + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + std::cerr << "Usage: " << argv[0] << " <path-to>/abook.mab" << std::endl; + std::cerr << "Example: " << argv[0] << " /home/johndoe/.thunderbird/m0tpqlky.default/abook.mab" << std::endl; + + return 1; + } + + OString aOString(argv[1]); + SAL_INFO("connectivity.mork", "abook.mab: " << aOString); + openAddressBook(aOString.getStr()); + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx new file mode 100644 index 000000000..8dc776877 --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.cxx @@ -0,0 +1,183 @@ +/* -*- 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 <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <cppuhelper/supportsservice.hxx> +#include "MMozillaBootstrap.hxx" +#include "MNSProfileDiscover.hxx" + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::mozilla; +using namespace connectivity::mozab; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +static MozillaBootstrap *pMozillaBootstrap=nullptr; +static Reference<XMozillaBootstrap> xMozillaBootstrap; +extern "C" SAL_DLLPUBLIC_EXPORT void* OMozillaBootstrap_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& ) +{ + if (!pMozillaBootstrap) + { + pMozillaBootstrap=new connectivity::mozab::MozillaBootstrap; + pMozillaBootstrap->Init(); + xMozillaBootstrap = pMozillaBootstrap; + } + return pMozillaBootstrap; +} + +MozillaBootstrap::MozillaBootstrap() + : OMozillaBootstrap_BASE(m_aMutex) +{ +} + +MozillaBootstrap::~MozillaBootstrap() +{ +} + +void MozillaBootstrap::Init() +{ + m_ProfileAccess.reset(new ProfileAccess); + bootupProfile(css::mozilla::MozillaProductType_Mozilla,OUString()); +} + +void MozillaBootstrap::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + OMozillaBootstrap_BASE::disposing(); +} + +OUString SAL_CALL MozillaBootstrap::getImplementationName( ) +{ + return MOZAB_MozillaBootstrap_IMPL_NAME; +} + +sal_Bool SAL_CALL MozillaBootstrap::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > SAL_CALL MozillaBootstrap::getSupportedServiceNames( ) +{ + // which service is supported + // for more information @see com.sun.star.mozilla.MozillaBootstrap + return { "com.sun.star.mozilla.MozillaBootstrap" }; +} + + +// XProfileDiscover +::sal_Int32 SAL_CALL MozillaBootstrap::getProfileCount( css::mozilla::MozillaProductType product) +{ + return m_ProfileAccess->getProfileCount(product); +} +::sal_Int32 SAL_CALL MozillaBootstrap::getProfileList( css::mozilla::MozillaProductType product, css::uno::Sequence< OUString >& list ) +{ + return m_ProfileAccess->getProfileList(product,list); +} +OUString SAL_CALL MozillaBootstrap::getDefaultProfile( css::mozilla::MozillaProductType product ) +{ + return m_ProfileAccess->getDefaultProfile(product); +} +OUString SAL_CALL MozillaBootstrap::getProfilePath( css::mozilla::MozillaProductType product, const OUString& profileName ) +{ + return m_ProfileAccess->getProfilePath(product,profileName); +} +sal_Bool SAL_CALL MozillaBootstrap::isProfileLocked( css::mozilla::MozillaProductType /*product*/, const OUString& /*profileName*/ ) +{ + return true; +} +sal_Bool SAL_CALL MozillaBootstrap::getProfileExists( css::mozilla::MozillaProductType product, const OUString& profileName ) +{ + return m_ProfileAccess->getProfileExists(product,profileName); +} + +// XProfileManager +::sal_Int32 SAL_CALL MozillaBootstrap::bootupProfile( css::mozilla::MozillaProductType, const OUString& ) +{ + return -1; +} +::sal_Int32 SAL_CALL MozillaBootstrap::shutdownProfile( ) +{ + return -1; +} +css::mozilla::MozillaProductType SAL_CALL MozillaBootstrap::getCurrentProduct( ) +{ + return css::mozilla::MozillaProductType_Default; +} +OUString SAL_CALL MozillaBootstrap::getCurrentProfile( ) +{ + return OUString(); +} +sal_Bool SAL_CALL MozillaBootstrap::isCurrentProfileLocked( ) +{ + return true; +} +OUString SAL_CALL MozillaBootstrap::setCurrentProfile( css::mozilla::MozillaProductType, const OUString& ) +{ + return OUString(); +} + +// XProxyRunner +::sal_Int32 SAL_CALL MozillaBootstrap::Run( const css::uno::Reference< css::mozilla::XCodeProxy >& ) +{ + return -1; +} + +static Reference< XInterface > createInstance( const Reference< XMultiServiceFactory >& rServiceManager ) +{ + MozillaBootstrap * pBootstrap = static_cast<MozillaBootstrap*>(OMozillaBootstrap_CreateInstance(rServiceManager)); + return *pBootstrap; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* mozbootstrap_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + + if (pServiceManager) + { + OUString aImplName( OUString::createFromAscii( pImplementationName ) ); + Reference< XSingleServiceFactory > xFactory; + if ( aImplName == "com.sun.star.comp.mozilla.MozillaBootstrap" ) + { + Sequence<OUString> aSNS { "com.sun.star.mozilla.MozillaBootstrap" }; + + xFactory = ::cppu::createSingleFactory( + static_cast< XMultiServiceFactory* > ( pServiceManager), + aImplName, createInstance, aSNS ); + } + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.hxx b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.hxx new file mode 100644 index 000000000..a727e3579 --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/MMozillaBootstrap.hxx @@ -0,0 +1,87 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MMOZILLABOOTSTRAP_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MMOZILLABOOTSTRAP_HXX + +#include <sal/config.h> + +#include <memory> + +#include <com/sun/star/mozilla/XMozillaBootstrap.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/compbase.hxx> + + +#define MOZAB_MozillaBootstrap_IMPL_NAME "com.sun.star.comp.mozilla.MozillaBootstrap" + +namespace connectivity +{ + namespace mozab + { + typedef ::cppu::WeakComponentImplHelper< css::mozilla::XMozillaBootstrap, + css::lang::XServiceInfo > OMozillaBootstrap_BASE; + class ProfileAccess; + class ProfileManager; + class MozillaBootstrap : public OMozillaBootstrap_BASE + { + private: + ::osl::Mutex m_aMutex; // mutex is need to control member access + virtual ~MozillaBootstrap() override; + std::unique_ptr<ProfileAccess> m_ProfileAccess; + public: + + void Init(); + MozillaBootstrap(); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XMozillaBootstrap + + // XProfileDiscover + virtual ::sal_Int32 SAL_CALL getProfileCount( css::mozilla::MozillaProductType product) override; + virtual ::sal_Int32 SAL_CALL getProfileList( css::mozilla::MozillaProductType product, css::uno::Sequence< OUString >& list ) override; + virtual OUString SAL_CALL getDefaultProfile( css::mozilla::MozillaProductType product ) override; + virtual OUString SAL_CALL getProfilePath( css::mozilla::MozillaProductType product, const OUString& profileName ) override; + virtual sal_Bool SAL_CALL isProfileLocked( css::mozilla::MozillaProductType product, const OUString& profileName ) override; + virtual sal_Bool SAL_CALL getProfileExists( css::mozilla::MozillaProductType product, const OUString& profileName ) override; + + // XProfileManager + virtual ::sal_Int32 SAL_CALL bootupProfile( css::mozilla::MozillaProductType product, const OUString& profileName ) override; + virtual ::sal_Int32 SAL_CALL shutdownProfile( ) override; + virtual css::mozilla::MozillaProductType SAL_CALL getCurrentProduct( ) override; + virtual OUString SAL_CALL getCurrentProfile( ) override; + virtual sal_Bool SAL_CALL isCurrentProfileLocked( ) override; + virtual OUString SAL_CALL setCurrentProfile( css::mozilla::MozillaProductType product, const OUString& profileName ) override; + + // XProxyRunner + virtual ::sal_Int32 SAL_CALL Run( const css::uno::Reference< css::mozilla::XCodeProxy >& aCode ) override; + }; + } + +} + +#endif // CONNECTIVITY_SMozillaBootstrap_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSFolders.cxx b/connectivity/source/drivers/mozab/bootstrap/MNSFolders.cxx new file mode 100644 index 000000000..2c92613d2 --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/MNSFolders.cxx @@ -0,0 +1,159 @@ +/* -*- 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 "MNSFolders.hxx" + +#ifdef UNIX +#include <string.h> +#endif // End UNIX + +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <stdlib.h> +#include <shlobj.h> +#include <objidl.h> +#endif // End _WIN32 +#include <osl/security.hxx> +#include <osl/file.hxx> +#include <osl/thread.h> + +using namespace ::com::sun::star::mozilla; + +namespace +{ + + OUString lcl_getUserDataDirectory() + { + ::osl::Security aSecurity; + OUString aConfigPath; + + #if defined(_WIN32) || defined(MACOSX) + aSecurity.getConfigDir( aConfigPath ); + #else + //This is to find the dir under which .mozilla/.thunderbird is created. + //mozilla doesn't honour XDG_CONFIG_HOME, so raw home dir required here + //not xdg-config dir + aSecurity.getHomeDir( aConfigPath ); + #endif + + return aConfigPath + "/"; + } + + + const size_t NB_PRODUCTS = 3; + const size_t NB_CANDIDATES = 4; + + // The order (index) of entries in DefaultProductDir and + // ProductRootEnvironmentVariable *must* match the constants + // (minus 1) in offapi/com/sun/star/mozilla/MozillaProductType.idl + // DO NOT CHANGE THE ORDER; ADD ONLY TO THE END + static const char* DefaultProductDir[NB_PRODUCTS][NB_CANDIDATES] = + { + #if defined(_WIN32) + { "Mozilla/SeaMonkey/", nullptr, nullptr, nullptr }, + { "Mozilla/Firefox/", nullptr, nullptr, nullptr }, + { "Thunderbird/", "Mozilla/Thunderbird/", nullptr, nullptr } + #elif defined(MACOSX) + { "../Mozilla/SeaMonkey/", nullptr, nullptr, nullptr }, + { "Firefox/", nullptr, nullptr, nullptr }, + { "../Thunderbird/", nullptr, nullptr, nullptr } + #else + { ".mozilla/seamonkey/", nullptr, nullptr, nullptr }, + { ".mozilla/firefox/", nullptr, nullptr, nullptr }, + { ".thunderbird/", ".mozilla-thunderbird/", ".mozilla/thunderbird/", ".icedove/" } + #endif + }; + + static const char* ProductRootEnvironmentVariable[NB_PRODUCTS] = + { + "MOZILLA_PROFILE_ROOT", + "MOZILLA_FIREFOX_PROFILE_ROOT", + "MOZILLA_THUNDERBIRD_PROFILE_ROOT", + }; + + + OUString const & lcl_guessProfileRoot( MozillaProductType _product ) + { + size_t productIndex = static_cast<int>(_product) - 1; + + static OUString s_productDirectories[NB_PRODUCTS]; + + if ( s_productDirectories[ productIndex ].isEmpty() ) + { + OUString sProductPath; + + // check whether we have an environment variable which help us + const char* pProfileByEnv = getenv( ProductRootEnvironmentVariable[ productIndex ] ); + if ( pProfileByEnv ) + { + sProductPath = OUString( pProfileByEnv, rtl_str_getLength( pProfileByEnv ), osl_getThreadTextEncoding() ); + // assume that this is fine, no further checks + } + else + { + OUString sProductDirCandidate; + const char pProfileRegistry[] = "profiles.ini"; + + // check all possible candidates + for ( size_t i=0; i<NB_CANDIDATES; ++i ) + { + if ( nullptr == DefaultProductDir[ productIndex ][ i ] ) + break; + + sProductDirCandidate = lcl_getUserDataDirectory() + + OUString::createFromAscii( DefaultProductDir[ productIndex ][ i ] ); + + // check existence + ::osl::DirectoryItem aRegistryItem; + ::osl::FileBase::RC result = ::osl::DirectoryItem::get( sProductDirCandidate + pProfileRegistry, aRegistryItem ); + if ( result == ::osl::FileBase::E_None ) + { + ::osl::FileStatus aStatus( osl_FileStatus_Mask_Validate ); + result = aRegistryItem.getFileStatus( aStatus ); + if ( result == ::osl::FileBase::E_None ) + { + // the registry file exists + break; + } + } + } + + ::osl::FileBase::getSystemPathFromFileURL( sProductDirCandidate, sProductPath ); + } + + s_productDirectories[ productIndex ] = sProductPath; + } + + return s_productDirectories[ productIndex ]; + } +} + + +OUString getRegistryDir(MozillaProductType product) +{ + if (product == MozillaProductType_Default) + return OUString(); + + return lcl_guessProfileRoot( product ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSFolders.hxx b/connectivity/source/drivers/mozab/bootstrap/MNSFolders.hxx new file mode 100644 index 000000000..50c992f23 --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/MNSFolders.hxx @@ -0,0 +1,31 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MNSFOLDERS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MNSFOLDERS_HXX + +#include <com/sun/star/mozilla/MozillaProductType.hpp> + +#include <rtl/ustring.hxx> + +OUString getRegistryDir(css::mozilla::MozillaProductType product); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.cxx b/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.cxx new file mode 100644 index 000000000..ae775b6fc --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.cxx @@ -0,0 +1,93 @@ +/* -*- 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 "MNSINIParser.hxx" +#include <com/sun/star/io/IOException.hpp> +#include <osl/file.h> +#include <rtl/byteseq.hxx> +#include <sal/log.hxx> + +IniParser::IniParser(OUString const & rIniName) +{ + OUString iniUrl; + if (osl_File_E_None != osl_getFileURLFromSystemPath(rIniName.pData, &iniUrl.pData)) + return; + + + oslFileHandle handle=nullptr; + oslFileError fileError = osl_File_E_INVAL; + try{ + if (!iniUrl.isEmpty()) + fileError = osl_openFile(iniUrl.pData, &handle, osl_File_OpenFlag_Read); + } + catch(const css::io::IOException&) + { + SAL_WARN("connectivity.mozab", "couldn't open file: " << iniUrl ); + } + + if (osl_File_E_None == fileError) + { + rtl::ByteSequence seq; + sal_uInt64 nSize = 0; + + osl_getFileSize(handle, &nSize); + OUString sectionName( "no name section" ); + while (true) + { + sal_uInt64 nPos; + if (osl_File_E_None != osl_getFilePos(handle, &nPos) || nPos >= nSize) + break; + if (osl_File_E_None != osl_readLine(handle, reinterpret_cast<sal_Sequence **>(&seq))) + break; + OString line(reinterpret_cast<const char *>(seq.getConstArray()), seq.getLength() ); + sal_Int32 nIndex = line.indexOf('='); + if (nIndex >= 1) + { + ini_Section *aSection = &mAllSection[sectionName]; + struct ini_NameValue nameValue; + nameValue.sName = OStringToOUString( + line.copy(0,nIndex).trim(), RTL_TEXTENCODING_ASCII_US ); + nameValue.sValue = OStringToOUString( + line.copy(nIndex+1).trim(), RTL_TEXTENCODING_UTF8 ); + + aSection->vVector.push_back(nameValue); + + } + else + { + sal_Int32 nIndexStart = line.indexOf('['); + sal_Int32 nIndexEnd = line.indexOf(']'); + if ( nIndexEnd > nIndexStart && nIndexStart >=0) + { + sectionName = OStringToOUString( + line.copy(nIndexStart + 1,nIndexEnd - nIndexStart -1).trim(), RTL_TEXTENCODING_ASCII_US ); + if (sectionName.isEmpty()) + sectionName = "no name section"; + } + } + } + osl_closeFile(handle); + } + else + { + SAL_INFO("connectivity.mozab", "couldn't open file: " << iniUrl ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.hxx b/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.hxx new file mode 100644 index 000000000..210553b73 --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/MNSINIParser.hxx @@ -0,0 +1,57 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MNSINIPARSER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MNSINIPARSER_HXX + +#include <rtl/ustring.hxx> + +#include <map> +#include <vector> + +struct ini_NameValue +{ + OUString sName; + OUString sValue; +}; + +typedef std::vector< + ini_NameValue +> NameValueVector; + +struct ini_Section +{ + NameValueVector vVector; +}; +typedef std::map<OUString, + ini_Section + >IniSectionMap; + + +class IniParser +{ + IniSectionMap mAllSection; +public: + IniSectionMap& getAllSection() { return mAllSection; } + /// @throws css::io::IOException + explicit IniParser(OUString const & rIniName); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.cxx b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.cxx new file mode 100644 index 000000000..4dd9110a6 --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.cxx @@ -0,0 +1,209 @@ +/* -*- 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 "MNSProfileDiscover.hxx" +#include "MNSFolders.hxx" +#include "MNSINIParser.hxx" + +namespace connectivity::mozab +{ + ProfileStruct::ProfileStruct() + { + } + + ProfileStruct::ProfileStruct(const OUString& aProfileName, + const OUString& aProfilePath) + : profileName(aProfileName) + , profilePath(aProfilePath) + { + } + + const OUString& ProfileStruct::getProfilePath() const + { + return profilePath; + } + + ProfileAccess::~ProfileAccess() + { + } + + ProfileAccess::ProfileAccess() + { + LoadProductsInfo(); + } + + void ProfileAccess::LoadProductsInfo() + { + //tdf#39279: LO should search Thunderbird first then Seamonkey and finally Firefox + //load thunderbird profiles to m_ProductProfileList + LoadXPToolkitProfiles(MozillaProductType_Thunderbird); + + //load SeaMonkey 2 profiles to m_ProductProfileList + LoadXPToolkitProfiles(MozillaProductType_Mozilla); + + //load firefox profiles to m_ProductProfileList + //firefox profile does not contain address book, but maybe others need them + LoadXPToolkitProfiles(MozillaProductType_Firefox); + } + //Thunderbird and firefox profiles are saved in profiles.ini + void ProfileAccess::LoadXPToolkitProfiles(MozillaProductType product) + { + sal_Int32 index=static_cast<sal_Int32>(product); + ProductStruct &rProduct = m_ProductProfileList[index]; + + OUString regDir = getRegistryDir(product); + OUString profilesIni = regDir + "profiles.ini"; + IniParser parser( profilesIni ); + IniSectionMap &rAllSection = parser.getAllSection(); + + for(auto& rSection : rAllSection) + { + ini_Section *aSection = &rSection.second; + OUString profileName; + OUString profilePath; + OUString sIsRelative; + OUString sIsDefault; + + for(auto& rValue : aSection->vVector) + { + struct ini_NameValue * aValue = &rValue; + if ( aValue->sName == "Name" ) + { + profileName = aValue->sValue; + } + else if ( aValue->sName == "IsRelative" ) + { + sIsRelative = aValue->sValue; + } + else if ( aValue->sName == "Path" ) + { + profilePath = aValue->sValue; + } + else if ( aValue->sName == "Default" ) + { + sIsDefault = aValue->sValue; + } + } + if (!(profileName.isEmpty() && profilePath.isEmpty())) + { + sal_Int32 isRelative = 0; + if (!sIsRelative.isEmpty()) + { + isRelative = sIsRelative.toInt32(); + } + + OUString fullProfilePath; + if(isRelative) + { + fullProfilePath = regDir + profilePath; + } + else + { + fullProfilePath = profilePath; + } + + rProduct.mProfileList[profileName] = ProfileStruct(profileName,fullProfilePath); + + sal_Int32 isDefault = 0; + if (!sIsDefault.isEmpty()) + { + isDefault = sIsDefault.toInt32(); + } + if (isDefault) + rProduct.mCurrentProfileName = profileName; + + } + + // Depending on TB versions, some generate "default" profile + // others "default-release" profile + // See https://support.mozilla.org/gl/questions/1264072 + // for some background info (the link quotes Firefox but it seems + // the same for TB). + if (profileName == "default-release") + { + rProduct.mCurrentProfileName = profileName; + break; + } + } + } + + OUString ProfileAccess::getProfilePath( css::mozilla::MozillaProductType product, const OUString& profileName ) + { + sal_Int32 index=static_cast<sal_Int32>(product); + ProductStruct &rProduct = m_ProductProfileList[index]; + if (rProduct.mProfileList.empty() || rProduct.mProfileList.find(profileName) == rProduct.mProfileList.end()) + { + //Profile not found + return OUString(); + } + else + return rProduct.mProfileList[profileName].getProfilePath(); + } + + ::sal_Int32 ProfileAccess::getProfileCount( css::mozilla::MozillaProductType product) + { + sal_Int32 index=static_cast<sal_Int32>(product); + ProductStruct &rProduct = m_ProductProfileList[index]; + return static_cast< ::sal_Int32 >(rProduct.mProfileList.size()); + } + ::sal_Int32 ProfileAccess::getProfileList( css::mozilla::MozillaProductType product, css::uno::Sequence< OUString >& list ) + { + sal_Int32 index=static_cast<sal_Int32>(product); + ProductStruct &rProduct = m_ProductProfileList[index]; + list.realloc(static_cast<sal_Int32>(rProduct.mProfileList.size())); + sal_Int32 i=0; + for(const auto& rEntry : rProduct.mProfileList) + { + const ProfileStruct& rProfile = rEntry.second; + list[i] = rProfile.getProfileName(); + i++; + } + + return static_cast< ::sal_Int32 >(rProduct.mProfileList.size()); + } + + OUString ProfileAccess::getDefaultProfile( css::mozilla::MozillaProductType product ) + { + sal_Int32 index=static_cast<sal_Int32>(product); + ProductStruct &rProduct = m_ProductProfileList[index]; + if (!rProduct.mCurrentProfileName.isEmpty()) + { + //default profile set in mozilla registry + return rProduct.mCurrentProfileName; + } + if (rProduct.mProfileList.empty()) + { + //there are not any profiles + return OUString(); + } + const ProfileStruct& rProfile = (*rProduct.mProfileList.begin()).second; + return rProfile.getProfileName(); + } + + bool ProfileAccess::getProfileExists( css::mozilla::MozillaProductType product, const OUString& profileName ) + { + sal_Int32 index=static_cast<sal_Int32>(product); + ProductStruct &rProduct = m_ProductProfileList[index]; + return rProduct.mProfileList.find(profileName) != rProduct.mProfileList.end(); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.hxx b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.hxx new file mode 100644 index 000000000..8921a9c4b --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/MNSProfileDiscover.hxx @@ -0,0 +1,90 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MNSPROFILEDISCOVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MNSPROFILEDISCOVER_HXX + +#include <sal/types.h> +#include <com/sun/star/mozilla/MozillaProductType.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/ustring.hxx> + +#include <vector> +#include <map> + +using namespace com::sun::star::mozilla; +namespace connectivity +{ + namespace mozab + { + class ProfileStruct; + } +} +typedef std::map<OUString, ::connectivity::mozab::ProfileStruct> ProfileList; +namespace connectivity +{ + namespace mozab + { + class ProfileStruct + { + public: + ProfileStruct(); + ProfileStruct(const OUString& aProfileName, const OUString &aProfilePath); + const OUString& getProfileName() const { return profileName;} + const OUString& getProfilePath() const; + private: + OUString profileName; + OUString profilePath; + }; + + class ProductStruct + { + public: + OUString mCurrentProfileName; + ProfileList mProfileList; + }; + + //Used to query profiles information + class ProfileAccess final + { + public: + ~ProfileAccess(); + ProfileAccess(); + /// @throws css::uno::RuntimeException + OUString getProfilePath( css::mozilla::MozillaProductType product, const OUString& profileName ); + /// @throws css::uno::RuntimeException + ::sal_Int32 getProfileCount( css::mozilla::MozillaProductType product ); + /// @throws css::uno::RuntimeException + ::sal_Int32 getProfileList( css::mozilla::MozillaProductType product, css::uno::Sequence< OUString >& list ); + /// @throws css::uno::RuntimeException + OUString getDefaultProfile( css::mozilla::MozillaProductType product ); + /// @throws css::uno::RuntimeException + bool getProfileExists( css::mozilla::MozillaProductType product, const OUString& profileName ); + private: + ProductStruct m_ProductProfileList[4]; + void LoadProductsInfo(); + void LoadXPToolkitProfiles(MozillaProductType product); + }; + + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_MOZAB_BOOTSTRAP_MNSPROFILEDISCOVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mozab/bootstrap/mozbootstrap.component b/connectivity/source/drivers/mozab/bootstrap/mozbootstrap.component new file mode 100644 index 000000000..848112c64 --- /dev/null +++ b/connectivity/source/drivers/mozab/bootstrap/mozbootstrap.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="mozbootstrap" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.mozilla.MozillaBootstrap"> + <service name="com.sun.star.mozilla.MozillaBootstrap"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx b/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx new file mode 100644 index 000000000..ad98bfa1a --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YCatalog.cxx @@ -0,0 +1,133 @@ +/* -*- 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 <mysql/YCatalog.hxx> +#include <mysql/YUsers.hxx> +#include <mysql/YTables.hxx> +#include <mysql/YViews.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <comphelper/types.hxx> + +using namespace connectivity; +using namespace connectivity::mysql; +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; + +OMySQLCatalog::OMySQLCatalog(const Reference<XConnection>& _xConnection) + : OCatalog(_xConnection) + , m_xConnection(_xConnection) +{ +} + +void OMySQLCatalog::refreshObjects(const Sequence<OUString>& _sKindOfObject, + ::std::vector<OUString>& _rNames) +{ + Reference<XResultSet> xResult = m_xMetaData->getTables(Any(), "%", "%", _sKindOfObject); + fillNames(xResult, _rNames); +} + +void OMySQLCatalog::refreshTables() +{ + ::std::vector<OUString> aVector; + + Sequence<OUString> sTableTypes(3); + sTableTypes[0] = "VIEW"; + sTableTypes[1] = "TABLE"; + sTableTypes[2] = "%"; // just to be sure to include anything else... + + refreshObjects(sTableTypes, aVector); + + if (m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset(new OTables(m_xMetaData, *this, m_aMutex, aVector)); +} + +void OMySQLCatalog::refreshViews() +{ + Sequence<OUString> aTypes{ "VIEW" }; + + // let's simply assume the server is new enough to support views. Current drivers + // as of this writing might not return the proper information in getTableTypes, so + // don't rely on it. + + ::std::vector<OUString> aVector; + refreshObjects(aTypes, aVector); + + if (m_pViews) + m_pViews->reFill(aVector); + else + m_pViews.reset(new OViews(m_xMetaData, *this, m_aMutex, aVector)); +} + +void OMySQLCatalog::refreshGroups() {} + +void OMySQLCatalog::refreshUsers() +{ + ::std::vector<OUString> aVector; + Reference<XStatement> xStmt = m_xConnection->createStatement(); + Reference<XResultSet> xResult = xStmt->executeQuery( + "SELECT grantee FROM information_schema.user_privileges GROUP BY grantee"); + if (xResult.is()) + { + Reference<XRow> xRow(xResult, UNO_QUERY); + while (xResult->next()) + aVector.push_back(xRow->getString(1)); + ::comphelper::disposeComponent(xResult); + } + ::comphelper::disposeComponent(xStmt); + + if (m_pUsers) + m_pUsers->reFill(aVector); + else + m_pUsers.reset(new OUsers(*this, m_aMutex, aVector, m_xConnection, this)); +} + +Any SAL_CALL OMySQLCatalog::queryInterface(const Type& rType) +{ + if (rType == cppu::UnoType<XGroupsSupplier>::get()) + return Any(); + + return OCatalog::queryInterface(rType); +} + +Sequence<Type> SAL_CALL OMySQLCatalog::getTypes() +{ + Sequence<Type> aTypes = OCatalog::getTypes(); + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + const Type* pBegin = aTypes.getConstArray(); + const Type* pEnd = pBegin + aTypes.getLength(); + for (; pBegin != pEnd; ++pBegin) + { + if (*pBegin != cppu::UnoType<XGroupsSupplier>::get()) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence<Type>(aOwnTypes.data(), aOwnTypes.size()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YColumns.cxx b/connectivity/source/drivers/mysql_jdbc/YColumns.cxx new file mode 100644 index 000000000..54beb77ca --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YColumns.cxx @@ -0,0 +1,72 @@ +/* -*- 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 <mysql/YColumns.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity::mysql; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OMySQLColumns::OMySQLColumns(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector) + : OColumnsHelper(_rParent, true /*_bCase*/, _rMutex, _rVector, true /*_bUseHardRef*/) +{ +} + +Reference<XPropertySet> OMySQLColumns::createDescriptor() { return new OMySQLColumn; } + +OMySQLColumn::OMySQLColumn() + : connectivity::sdbcx::OColumn(true) +{ + construct(); +} + +void OMySQLColumn::construct() +{ + m_sAutoIncrement = "auto_increment"; + registerProperty( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION), + PROPERTY_ID_AUTOINCREMENTCREATION, 0, &m_sAutoIncrement, + cppu::UnoType<decltype(m_sAutoIncrement)>::get()); +} + +::cppu::IPropertyArrayHelper* OMySQLColumn::createArrayHelper(sal_Int32 /*_nId*/) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& SAL_CALL OMySQLColumn::getInfoHelper() +{ + return *OMySQLColumn_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +Sequence<OUString> SAL_CALL OMySQLColumn::getSupportedServiceNames() +{ + return { "com.sun.star.sdbcx.Column" }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YDriver.cxx b/connectivity/source/drivers/mysql_jdbc/YDriver.cxx new file mode 100644 index 000000000..de6c0fdab --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YDriver.cxx @@ -0,0 +1,418 @@ +/* -*- 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 <mysql/YDriver.hxx> +#include <mysql/YCatalog.hxx> +#include <comphelper/namedvaluecollection.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/dbexception.hxx> +#include <connectivity/dbcharset.hxx> +#include <com/sun/star/sdbc/DriverManager.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <TConnection.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + +namespace connectivity +{ +using namespace mysql; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +namespace mysql +{ +Reference<XInterface> +ODriverDelegator_CreateInstance(const Reference<css::lang::XMultiServiceFactory>& _rxFac) +{ + return *(new ODriverDelegator(comphelper::getComponentContext(_rxFac))); +} +} + +namespace +{ +OUString getJavaDriverClass(css::uno::Sequence<css::beans::PropertyValue> const& info) +{ + return comphelper::NamedValueCollection(info).getOrDefault("JavaDriverClass", + OUString("com.mysql.jdbc.Driver")); +} +} + +ODriverDelegator::ODriverDelegator(const Reference<XComponentContext>& _rxContext) + : ODriverDelegator_BASE(m_aMutex) + , m_xContext(_rxContext) +{ +} + +ODriverDelegator::~ODriverDelegator() +{ + try + { + ::comphelper::disposeComponent(m_xODBCDriver); + ::comphelper::disposeComponent(m_xNativeDriver); + for (auto& rEntry : m_aJdbcDrivers) + ::comphelper::disposeComponent(rEntry.second); + } + catch (const Exception&) + { + } +} + +void ODriverDelegator::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + for (auto const& connection : m_aConnections) + { + Reference<XInterface> xTemp = connection.first.get(); + ::comphelper::disposeComponent(xTemp); + } + m_aConnections.clear(); + TWeakPairVector().swap(m_aConnections); + + ODriverDelegator_BASE::disposing(); +} + +namespace +{ +enum class T_DRIVERTYPE +{ + Odbc, + Jdbc, + Native +}; + +bool isOdbcUrl(const OUString& _sUrl) { return _sUrl.startsWith("sdbc:mysql:odbc:"); } + +bool isNativeUrl(const OUString& _sUrl) { return _sUrl.startsWith("sdbc:mysql:mysqlc:"); } + +T_DRIVERTYPE lcl_getDriverType(const OUString& _sUrl) +{ + T_DRIVERTYPE eRet = T_DRIVERTYPE::Jdbc; + if (isOdbcUrl(_sUrl)) + eRet = T_DRIVERTYPE::Odbc; + else if (isNativeUrl(_sUrl)) + eRet = T_DRIVERTYPE::Native; + return eRet; +} + +OUString transformUrl(const OUString& _sUrl) +{ + OUString sNewUrl = _sUrl.copy(11); + if (isOdbcUrl(_sUrl)) + sNewUrl = "sdbc:" + sNewUrl; + else if (isNativeUrl(_sUrl)) + sNewUrl = "sdbc:" + sNewUrl; + else + { + sNewUrl = "jdbc:mysql://" + sNewUrl.copy(5); + } + return sNewUrl; +} + +Reference<XDriver> lcl_loadDriver(const Reference<XComponentContext>& _rxContext, + const OUString& _sUrl) +{ + Reference<XDriverManager2> xDriverAccess = DriverManager::create(_rxContext); + Reference<XDriver> xDriver = xDriverAccess->getDriverByURL(_sUrl); + return xDriver; +} + +Sequence<PropertyValue> lcl_convertProperties(T_DRIVERTYPE _eType, + const Sequence<PropertyValue>& info, + const OUString& _sUrl) +{ + std::vector<PropertyValue> aProps; + const PropertyValue* pSupported = info.getConstArray(); + const PropertyValue* pEnd = pSupported + info.getLength(); + + aProps.reserve(info.getLength() + 5); + bool jdc = false; + for (; pSupported != pEnd; ++pSupported) + { + aProps.push_back(*pSupported); + if (pSupported->Name == "JavaDriverClass") + { + jdc = true; + } + } + + if (_eType == T_DRIVERTYPE::Odbc) + { + aProps.push_back(PropertyValue("Silent", 0, makeAny(true), PropertyState_DIRECT_VALUE)); + aProps.push_back(PropertyValue("PreventGetVersionColumns", 0, makeAny(true), + PropertyState_DIRECT_VALUE)); + } + else if (_eType == T_DRIVERTYPE::Jdbc) + { + if (!jdc) + { + aProps.push_back(PropertyValue("JavaDriverClass", 0, + makeAny(OUString("com.mysql.jdbc.Driver")), + PropertyState_DIRECT_VALUE)); + } + } + else + { + aProps.push_back( + PropertyValue("PublicConnectionURL", 0, makeAny(_sUrl), PropertyState_DIRECT_VALUE)); + } + aProps.push_back( + PropertyValue("IsAutoRetrievingEnabled", 0, makeAny(true), PropertyState_DIRECT_VALUE)); + aProps.push_back(PropertyValue("AutoRetrievingStatement", 0, + makeAny(OUString("SELECT LAST_INSERT_ID()")), + PropertyState_DIRECT_VALUE)); + aProps.push_back( + PropertyValue("ParameterNameSubstitution", 0, makeAny(true), PropertyState_DIRECT_VALUE)); + return Sequence<PropertyValue>(aProps.data(), aProps.size()); +} +} + +Reference<XDriver> ODriverDelegator::loadDriver(const OUString& url, + const Sequence<PropertyValue>& info) +{ + Reference<XDriver> xDriver; + const OUString sCuttedUrl = transformUrl(url); + const T_DRIVERTYPE eType = lcl_getDriverType(url); + if (eType == T_DRIVERTYPE::Odbc) + { + if (!m_xODBCDriver.is()) + m_xODBCDriver = lcl_loadDriver(m_xContext, sCuttedUrl); + xDriver = m_xODBCDriver; + } // if ( bIsODBC ) + else if (eType == T_DRIVERTYPE::Native) + { + if (!m_xNativeDriver.is()) + m_xNativeDriver = lcl_loadDriver(m_xContext, sCuttedUrl); + xDriver = m_xNativeDriver; + } + else + { + OUString sDriverClass(getJavaDriverClass(info)); + TJDBCDrivers::iterator aFind = m_aJdbcDrivers.find(sDriverClass); + if (aFind == m_aJdbcDrivers.end()) + aFind = m_aJdbcDrivers.emplace(sDriverClass, lcl_loadDriver(m_xContext, sCuttedUrl)) + .first; + xDriver = aFind->second; + } + + return xDriver; +} + +Reference<XConnection> SAL_CALL ODriverDelegator::connect(const OUString& url, + const Sequence<PropertyValue>& info) +{ + Reference<XConnection> xConnection; + if (acceptsURL(url)) + { + Reference<XDriver> xDriver = loadDriver(url, info); + if (xDriver.is()) + { + OUString sCuttedUrl = transformUrl(url); + const T_DRIVERTYPE eType = lcl_getDriverType(url); + Sequence<PropertyValue> aConvertedProperties = lcl_convertProperties(eType, info, url); + if (eType == T_DRIVERTYPE::Jdbc) + { + ::comphelper::NamedValueCollection aSettings(info); + OUString sIanaName = aSettings.getOrDefault("CharSet", OUString()); + if (!sIanaName.isEmpty()) + { + ::dbtools::OCharsetMap aLookupIanaName; + ::dbtools::OCharsetMap::const_iterator aLookup + = aLookupIanaName.findIanaName(sIanaName); + if (aLookup != aLookupIanaName.end()) + { + OUString sAdd; + if (RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding()) + { + static const char s_sCharSetOp[] = "useUnicode=true&"; + if (!sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp)) + { + sAdd = s_sCharSetOp; + } // if ( !sCuttedUrl.matchIgnoreAsciiCase(s_sCharSetOp) ) + } // if ( RTL_TEXTENCODING_UTF8 == (*aLookup).getEncoding() ) + if (sCuttedUrl.indexOf('?') == -1) + sCuttedUrl += "?"; + else + sCuttedUrl += "&"; + sCuttedUrl += sAdd + "characterEncoding=" + sIanaName; + } + } + } // if ( !bIsODBC ) + + xConnection = xDriver->connect(sCuttedUrl, aConvertedProperties); + if (xConnection.is()) + { + // now we have to set the URL to get the correct answer for metadata()->getURL() + auto pMetaConnection + = comphelper::getUnoTunnelImplementation<OMetaConnection>(xConnection); + if (pMetaConnection) + pMetaConnection->setURL(url); + m_aConnections.push_back( + TWeakPair(WeakReferenceHelper(xConnection), + TWeakConnectionPair(WeakReferenceHelper(), pMetaConnection))); + } + } + } + return xConnection; +} + +sal_Bool SAL_CALL ODriverDelegator::acceptsURL(const OUString& url) +{ + Sequence<PropertyValue> info; + + bool bOK = url.startsWith("sdbc:mysql:odbc:") || url.startsWith("sdbc:mysql:jdbc:") + || (url.startsWith("sdbc:mysql:mysqlc:") && loadDriver(url, info).is()); + return bOK; +} + +Sequence<DriverPropertyInfo> SAL_CALL +ODriverDelegator::getPropertyInfo(const OUString& url, const Sequence<PropertyValue>& info) +{ + std::vector<DriverPropertyInfo> aDriverInfo; + if (!acceptsURL(url)) + return Sequence<DriverPropertyInfo>(); + + Sequence<OUString> aBoolean(2); + aBoolean[0] = "0"; + aBoolean[1] = "1"; + + aDriverInfo.push_back(DriverPropertyInfo("CharSet", "CharSet of the database.", false, + OUString(), Sequence<OUString>())); + aDriverInfo.push_back(DriverPropertyInfo("SuppressVersionColumns", + "Display version columns (when available).", false, + "0", aBoolean)); + const T_DRIVERTYPE eType = lcl_getDriverType(url); + if (eType == T_DRIVERTYPE::Jdbc) + { + aDriverInfo.push_back(DriverPropertyInfo("JavaDriverClass", "The JDBC driver class name.", + true, getJavaDriverClass(info), + Sequence<OUString>())); + } + else if (eType == T_DRIVERTYPE::Native) + { + aDriverInfo.push_back(DriverPropertyInfo( + "LocalSocket", "The file path of a socket to connect to a local MySQL server.", false, + OUString(), Sequence<OUString>())); + aDriverInfo.push_back(DriverPropertyInfo( + "NamedPipe", "The name of a pipe to connect to a local MySQL server.", false, + OUString(), Sequence<OUString>())); + } + + return Sequence<DriverPropertyInfo>(aDriverInfo.data(), aDriverInfo.size()); +} + +sal_Int32 SAL_CALL ODriverDelegator::getMajorVersion() { return 1; } + +sal_Int32 SAL_CALL ODriverDelegator::getMinorVersion() { return 0; } + +Reference<XTablesSupplier> SAL_CALL +ODriverDelegator::getDataDefinitionByConnection(const Reference<XConnection>& connection) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(ODriverDelegator_BASE::rBHelper.bDisposed); + + Reference<XTablesSupplier> xTab; + auto pConnection = comphelper::getUnoTunnelImplementation<OMetaConnection>(connection); + if (pConnection) + { + TWeakPairVector::iterator i + = std::find_if(m_aConnections.begin(), m_aConnections.end(), + [&pConnection](const TWeakPairVector::value_type& rConnection) { + return rConnection.second.second == pConnection; + }); + if (i != m_aConnections.end()) + { + xTab.set(i->second.first.get(), UNO_QUERY); + if (!xTab.is()) + { + xTab = new OMySQLCatalog(connection); + i->second.first = WeakReferenceHelper(xTab); + } + } + } // if (pConnection) + if (!xTab.is()) + { + TWeakPairVector::iterator i + = std::find_if(m_aConnections.begin(), m_aConnections.end(), + [&connection](const TWeakPairVector::value_type& rConnection) { + Reference<XConnection> xTemp(rConnection.first.get(), UNO_QUERY); + return xTemp == connection; + }); + if (i != m_aConnections.end()) + { + xTab.set(i->second.first.get(), UNO_QUERY); + if (!xTab.is()) + { + xTab = new OMySQLCatalog(connection); + i->second.first = WeakReferenceHelper(xTab); + } + } + } + return xTab; +} + +Reference<XTablesSupplier> SAL_CALL +ODriverDelegator::getDataDefinitionByURL(const OUString& url, const Sequence<PropertyValue>& info) +{ + if (!acceptsURL(url)) + { + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage, *this); + } // if ( ! acceptsURL(url) ) + + return getDataDefinitionByConnection(connect(url, info)); +} + +// XServiceInfo + +OUString ODriverDelegator::getImplementationName_Static() +{ + return "org.openoffice.comp.drivers.MySQL.Driver"; +} + +Sequence<OUString> ODriverDelegator::getSupportedServiceNames_Static() +{ + return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" }; +} + +OUString SAL_CALL ODriverDelegator::getImplementationName() +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL ODriverDelegator::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence<OUString> SAL_CALL ODriverDelegator::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +} // namespace connectivity + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YTable.cxx b/connectivity/source/drivers/mysql_jdbc/YTable.cxx new file mode 100644 index 000000000..7959bd9d3 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YTable.cxx @@ -0,0 +1,330 @@ +/* -*- 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 <mysql/YTable.hxx> +#include <mysql/YTables.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <comphelper/property.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/sdbcx/VColumn.hxx> +#include <connectivity/TKeys.hxx> +#include <connectivity/TIndexes.hxx> +#include <mysql/YColumns.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity::mysql; +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +namespace connectivity::mysql +{ +namespace +{ +class OMySQLKeysHelper : public OKeysHelper +{ +protected: + virtual OUString getDropForeignKey() const override { return " DROP FOREIGN KEY "; } + +public: + OMySQLKeysHelper(OTableHelper* _pTable, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector) + : OKeysHelper(_pTable, _rMutex, _rVector) + { + } +}; +} +} + +OMySQLTable::OMySQLTable(sdbcx::OCollection* _pTables, const Reference<XConnection>& _xConnection) + : OTableHelper(_pTables, _xConnection, true) +{ + // we create a new table here, so we should have all the rights or ;-) + m_nPrivileges = Privilege::DROP | Privilege::REFERENCE | Privilege::ALTER | Privilege::CREATE + | Privilege::READ | Privilege::DELETE | Privilege::UPDATE | Privilege::INSERT + | Privilege::SELECT; + construct(); +} + +OMySQLTable::OMySQLTable(sdbcx::OCollection* _pTables, const Reference<XConnection>& _xConnection, + const OUString& Name, const OUString& Type, const OUString& Description, + const OUString& SchemaName, const OUString& CatalogName, + sal_Int32 _nPrivileges) + : OTableHelper(_pTables, _xConnection, true, Name, Type, Description, SchemaName, CatalogName) + , m_nPrivileges(_nPrivileges) +{ + construct(); +} + +void OMySQLTable::construct() +{ + OTableHelper::construct(); + if (!isNew()) + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES), + PROPERTY_ID_PRIVILEGES, PropertyAttribute::READONLY, &m_nPrivileges, + cppu::UnoType<decltype(m_nPrivileges)>::get()); +} + +::cppu::IPropertyArrayHelper* OMySQLTable::createArrayHelper(sal_Int32 /*_nId*/) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& OMySQLTable::getInfoHelper() +{ + return *static_cast<OMySQLTable_PROP*>(this)->getArrayHelper(isNew() ? 1 : 0); +} + +sdbcx::OCollection* OMySQLTable::createColumns(const ::std::vector<OUString>& _rNames) +{ + OMySQLColumns* pColumns = new OMySQLColumns(*this, m_aMutex, _rNames); + pColumns->setParent(this); + return pColumns; +} + +sdbcx::OCollection* OMySQLTable::createKeys(const ::std::vector<OUString>& _rNames) +{ + return new OMySQLKeysHelper(this, m_aMutex, _rNames); +} + +sdbcx::OCollection* OMySQLTable::createIndexes(const ::std::vector<OUString>& _rNames) +{ + return new OIndexesHelper(this, m_aMutex, _rNames); +} + +Sequence<sal_Int8> OMySQLTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OMySQLTable::getSomething(const Sequence<sal_Int8>& rId) +{ + return (isUnoTunnelId<OMySQLTable>(rId)) ? reinterpret_cast<sal_Int64>(this) + : OTable_TYPEDEF::getSomething(rId); +} + +// XAlterTable +void SAL_CALL OMySQLTable::alterColumnByName(const OUString& colName, + const Reference<XPropertySet>& descriptor) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed( +#ifdef __GNUC__ + ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed +#else + rBHelper.bDisposed +#endif + ); + + if (!m_xColumns || !m_xColumns->hasByName(colName)) + throw NoSuchElementException(colName, *this); + + if (!isNew()) + { + // first we have to check what should be altered + Reference<XPropertySet> xProp; + m_xColumns->getByName(colName) >>= xProp; + // first check the types + sal_Int32 nOldType = 0, nNewType = 0, nOldPrec = 0, nNewPrec = 0, nOldScale = 0, + nNewScale = 0; + + ::dbtools::OPropertyMap& rProp = OMetaConnection::getPropMap(); + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nOldType; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPE)) >>= nNewType; + // and precisions and scale + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nOldPrec; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_PRECISION)) >>= nNewPrec; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nOldScale; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_SCALE)) >>= nNewScale; + // second: check the "is nullable" value + sal_Int32 nOldNullable = 0, nNewNullable = 0; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nOldNullable; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNewNullable; + + // check also the auto_increment + bool bOldAutoIncrement = false, bAutoIncrement = false; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) + >>= bOldAutoIncrement; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT)) + >>= bAutoIncrement; + bool bColumnNameChanged = false; + OUString sOldDesc, sNewDesc; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sOldDesc; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DESCRIPTION)) >>= sNewDesc; + + if (nOldType != nNewType || nOldPrec != nNewPrec || nOldScale != nNewScale + || nNewNullable != nOldNullable || bOldAutoIncrement != bAutoIncrement + || sOldDesc != sNewDesc) + { + // special handling because they changed the type names to distinguish + // if a column should be an auto_increment one + if (bOldAutoIncrement != bAutoIncrement) + { + OUString sTypeName; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME)) + >>= sTypeName; + + static const char s_sAutoIncrement[] = "auto_increment"; + if (bAutoIncrement) + { + if (sTypeName.indexOf(s_sAutoIncrement) == -1) + { + sTypeName += OUStringLiteral(" ") + s_sAutoIncrement; + descriptor->setPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME), + makeAny(sTypeName)); + } + } + else + { + if (!sTypeName.isEmpty()) + { + sal_Int32 nIndex = sTypeName.indexOf(s_sAutoIncrement); + if (nIndex != -1) + { + sTypeName = sTypeName.copy(0, nIndex); + descriptor->setPropertyValue(rProp.getNameByIndex(PROPERTY_ID_TYPENAME), + makeAny(sTypeName)); + } + } + } + } + alterColumnType(nNewType, colName, descriptor); + bColumnNameChanged = true; + } + + // third: check the default values + OUString sNewDefault, sOldDefault; + xProp->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) >>= sOldDefault; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_DEFAULTVALUE)) + >>= sNewDefault; + + if (!sOldDefault.isEmpty()) + { + dropDefaultValue(colName); + if (!sNewDefault.isEmpty() && sOldDefault != sNewDefault) + alterDefaultValue(sNewDefault, colName); + } + else if (!sNewDefault.isEmpty()) + alterDefaultValue(sNewDefault, colName); + + // now we should look if the name of the column changed + OUString sNewColumnName; + descriptor->getPropertyValue(rProp.getNameByIndex(PROPERTY_ID_NAME)) >>= sNewColumnName; + if (!sNewColumnName.equalsIgnoreAsciiCase(colName) && !bColumnNameChanged) + { + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql = getAlterTableColumnPart() + " CHANGE " + + ::dbtools::quoteName(sQuote, colName) + " " + + OTables::adjustSQL(::dbtools::createStandardColumnPart( + descriptor, getConnection(), static_cast<OTables*>(m_pTables), + getTypeCreatePattern())); + executeStatement(sSql); + } + m_xColumns->refresh(); + } + else + { + if (m_xColumns) + { + m_xColumns->dropByName(colName); + m_xColumns->appendByDescriptor(descriptor); + } + } +} + +void OMySQLTable::alterColumnType(sal_Int32 nNewType, const OUString& _rColName, + const Reference<XPropertySet>& _xDescriptor) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql + = getAlterTableColumnPart() + " CHANGE " + ::dbtools::quoteName(sQuote, _rColName) + " "; + + OColumn* pColumn = new OColumn(true); + Reference<XPropertySet> xProp = pColumn; + ::comphelper::copyProperties(_xDescriptor, xProp); + xProp->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), + makeAny(nNewType)); + + sSql += OTables::adjustSQL(::dbtools::createStandardColumnPart( + xProp, getConnection(), static_cast<OTables*>(m_pTables), getTypeCreatePattern())); + executeStatement(sSql); +} + +OUString OMySQLTable::getTypeCreatePattern() const { return "(M,D)"; } + +void OMySQLTable::alterDefaultValue(const OUString& _sNewDefault, const OUString& _rColName) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql = getAlterTableColumnPart() + " ALTER " + ::dbtools::quoteName(sQuote, _rColName) + + " SET DEFAULT '" + _sNewDefault + "'"; + + executeStatement(sSql); +} + +void OMySQLTable::dropDefaultValue(const OUString& _rColName) +{ + const OUString sQuote = getMetaData()->getIdentifierQuoteString(); + OUString sSql = getAlterTableColumnPart() + " ALTER " + ::dbtools::quoteName(sQuote, _rColName) + + " DROP DEFAULT"; + + executeStatement(sSql); +} + +OUString OMySQLTable::getAlterTableColumnPart() const +{ + OUString sSql("ALTER TABLE "); + + OUString sComposedName( + ::dbtools::composeTableName(getMetaData(), m_CatalogName, m_SchemaName, m_Name, true, + ::dbtools::EComposeRule::InTableDefinitions)); + sSql += sComposedName; + + return sSql; +} + +void OMySQLTable::executeStatement(const OUString& _rStatement) +{ + OUString sSQL = _rStatement; + if (sSQL.endsWith(",")) + sSQL = sSQL.replaceAt(sSQL.getLength() - 1, 1, ")"); + + Reference<XStatement> xStmt = getConnection()->createStatement(); + if (xStmt.is()) + { + xStmt->execute(sSQL); + ::comphelper::disposeComponent(xStmt); + } +} + +OUString OMySQLTable::getRenameStart() const { return "RENAME TABLE "; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YTables.cxx b/connectivity/source/drivers/mysql_jdbc/YTables.cxx new file mode 100644 index 000000000..e21e05fb2 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YTables.cxx @@ -0,0 +1,210 @@ +/* -*- 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 <mysql/YTables.hxx> +#include <mysql/YViews.hxx> +#include <mysql/YTable.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <mysql/YCatalog.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace ::cppu; +using namespace connectivity::mysql; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace dbtools; + +sdbcx::ObjectType OTables::createObject(const OUString& _rName) +{ + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + + Sequence<OUString> sTableTypes(3); + sTableTypes[0] = "VIEW"; + sTableTypes[1] = "TABLE"; + sTableTypes[2] = "%"; // just to be sure to include anything else... + + Any aCatalog; + if (!sCatalog.isEmpty()) + aCatalog <<= sCatalog; + Reference<XResultSet> xResult = m_xMetaData->getTables(aCatalog, sSchema, sTable, sTableTypes); + + sdbcx::ObjectType xRet; + if (xResult.is()) + { + Reference<XRow> xRow(xResult, UNO_QUERY); + if (xResult->next()) // there can be only one table with this name + { + sal_Int32 const nPrivileges = Privilege::DROP | Privilege::REFERENCE | Privilege::ALTER + | Privilege::CREATE | Privilege::READ | Privilege::DELETE + | Privilege::UPDATE | Privilege::INSERT + | Privilege::SELECT; + + OMySQLTable* pRet = new OMySQLTable( + this, static_cast<OMySQLCatalog&>(m_rParent).getConnection(), sTable, + xRow->getString(4), xRow->getString(5), sSchema, sCatalog, nPrivileges); + xRet = pRet; + } + ::comphelper::disposeComponent(xResult); + } + + return xRet; +} + +void OTables::impl_refresh() { static_cast<OMySQLCatalog&>(m_rParent).refreshTables(); } + +void OTables::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference<XPropertySet> OTables::createDescriptor() +{ + return new OMySQLTable(this, static_cast<OMySQLCatalog&>(m_rParent).getConnection()); +} + +// XAppend +sdbcx::ObjectType OTables::appendObject(const OUString& _rForName, + const Reference<XPropertySet>& descriptor) +{ + createTable(descriptor); + return createObject(_rForName); +} + +// XDrop +void OTables::dropObject(sal_Int32 _nPos, const OUString& _sElementName) +{ + Reference<XInterface> xObject(getObject(_nPos)); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject); + if (bIsNew) + return; + + Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, _sElementName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + + OUString aSql("DROP "); + + Reference<XPropertySet> xProp(xObject, UNO_QUERY); + bool bIsView = xProp.is() + && ::comphelper::getString(xProp->getPropertyValue( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) + == "VIEW"; + if (bIsView) // here we have a view + aSql += "VIEW "; + else + aSql += "TABLE "; + + OUString sComposedName(::dbtools::composeTableName( + m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InDataManipulation)); + aSql += sComposedName; + Reference<XStatement> xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + // if no exception was thrown we must delete it from the views + if (bIsView) + { + OViews* pViews + = static_cast<OViews*>(static_cast<OMySQLCatalog&>(m_rParent).getPrivateViews()); + if (pViews && pViews->hasByName(_sElementName)) + pViews->dropByNameImpl(_sElementName); + } +} + +OUString OTables::adjustSQL(const OUString& _sSql) +{ + OUString sSQL = _sSql; + static const char s_sUNSIGNED[] = "UNSIGNED"; + sal_Int32 nIndex = sSQL.indexOf(s_sUNSIGNED); + while (nIndex != -1) + { + sal_Int32 nParen = sSQL.indexOf(')', nIndex); + sal_Int32 nPos = nIndex + strlen(s_sUNSIGNED); + OUString sNewUnsigned(sSQL.copy(nPos, nParen - nPos + 1)); + sSQL = sSQL.replaceAt(nIndex, strlen(s_sUNSIGNED) + sNewUnsigned.getLength(), + sNewUnsigned + s_sUNSIGNED); + nIndex = sSQL.indexOf(s_sUNSIGNED, nIndex + strlen(s_sUNSIGNED) + sNewUnsigned.getLength()); + } + return sSQL; +} + +void OTables::createTable(const Reference<XPropertySet>& descriptor) +{ + const Reference<XConnection> xConnection + = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + const OUString aSql + = adjustSQL(::dbtools::createSqlCreateTableStatement(descriptor, xConnection)); + Reference<XStatement> xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } +} + +void OTables::appendNew(const OUString& _rsNewTable) +{ + insertElement(_rsNewTable, nullptr); + + // notify our container listeners + ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_rsNewTable), Any(), Any()); + OInterfaceIteratorHelper2 aListenerLoop(m_aContainerListeners); + while (aListenerLoop.hasMoreElements()) + static_cast<XContainerListener*>(aListenerLoop.next())->elementInserted(aEvent); +} + +OUString OTables::getNameForObject(const sdbcx::ObjectType& _xObject) +{ + OSL_ENSURE(_xObject.is(), "OTables::getNameForObject: Object is NULL!"); + return ::dbtools::composeTableName(m_xMetaData, _xObject, + ::dbtools::EComposeRule::InDataManipulation, false); +} + +void OTables::addComment(const Reference<XPropertySet>& descriptor, OUStringBuffer& _rOut) +{ + OUString sDesc; + descriptor->getPropertyValue( + OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION)) + >>= sDesc; + if (!sDesc.isEmpty()) + { + _rOut.append(" COMMENT '"); + _rOut.append(sDesc); + _rOut.append("'"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YUser.cxx b/connectivity/source/drivers/mysql_jdbc/YUser.cxx new file mode 100644 index 000000000..b683fe2b2 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YUser.cxx @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <mysql/YUser.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbcx/PrivilegeObject.hpp> +#include <TConnection.hxx> +#include <strings.hrc> +#include <comphelper/types.hxx> + +using namespace connectivity; +using namespace connectivity::mysql; +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; + +OMySQLUser::OMySQLUser(const css::uno::Reference<css::sdbc::XConnection>& _xConnection) + : connectivity::sdbcx::OUser(true) + , m_xConnection(_xConnection) +{ + construct(); +} + +OMySQLUser::OMySQLUser(const css::uno::Reference<css::sdbc::XConnection>& _xConnection, + const OUString& Name) + : connectivity::sdbcx::OUser(Name, true) + , m_xConnection(_xConnection) +{ + construct(); +} + +void OMySQLUser::refreshGroups() {} + +OUserExtend::OUserExtend(const css::uno::Reference<css::sdbc::XConnection>& _xConnection) + : OMySQLUser(_xConnection) +{ + construct(); +} + +void OUserExtend::construct() +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD), + PROPERTY_ID_PASSWORD, 0, &m_Password, ::cppu::UnoType<OUString>::get()); +} + +cppu::IPropertyArrayHelper* OUserExtend::createArrayHelper() const +{ + Sequence<Property> aProps; + describeProperties(aProps); + return new cppu::OPropertyArrayHelper(aProps); +} + +cppu::IPropertyArrayHelper& OUserExtend::getInfoHelper() +{ + return *OUserExtend_PROP::getArrayHelper(); +} +typedef connectivity::sdbcx::OUser_BASE OUser_BASE_RBHELPER; + +sal_Int32 SAL_CALL OMySQLUser::getPrivileges(const OUString& objName, sal_Int32 objType) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + sal_Int32 nRights, nRightsWithGrant; + findPrivilegesAndGrantPrivileges(objName, objType, nRights, nRightsWithGrant); + return nRights; +} + +void OMySQLUser::findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType, + sal_Int32& nRights, sal_Int32& nRightsWithGrant) +{ + nRightsWithGrant = nRights = 0; + // first we need to create the sql stmt to select the privs + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(xMeta, objName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + Reference<XResultSet> xRes; + switch (objType) + { + case PrivilegeObject::TABLE: + case PrivilegeObject::VIEW: + { + Any aCatalog; + if (!sCatalog.isEmpty()) + aCatalog <<= sCatalog; + xRes = xMeta->getTablePrivileges(aCatalog, sSchema, sTable); + } + break; + + case PrivilegeObject::COLUMN: + { + Any aCatalog; + if (!sCatalog.isEmpty()) + aCatalog <<= sCatalog; + xRes = xMeta->getColumnPrivileges(aCatalog, sSchema, sTable, "%"); + } + break; + } + + if (!xRes.is()) + return; + + static const char sYes[] = "YES"; + + nRightsWithGrant = nRights = 0; + + Reference<XRow> xCurrentRow(xRes, UNO_QUERY); + while (xCurrentRow.is() && xRes->next()) + { + OUString sGrantee = xCurrentRow->getString(5); + OUString sPrivilege = xCurrentRow->getString(6); + OUString sGrantable = xCurrentRow->getString(7); + + if (!m_Name.equalsIgnoreAsciiCase(sGrantee)) + continue; + + if (sPrivilege.equalsIgnoreAsciiCase("SELECT")) + { + nRights |= Privilege::SELECT; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::SELECT; + } + else if (sPrivilege.equalsIgnoreAsciiCase("INSERT")) + { + nRights |= Privilege::INSERT; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::INSERT; + } + else if (sPrivilege.equalsIgnoreAsciiCase("UPDATE")) + { + nRights |= Privilege::UPDATE; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::UPDATE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("DELETE")) + { + nRights |= Privilege::DELETE; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::DELETE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("READ")) + { + nRights |= Privilege::READ; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::READ; + } + else if (sPrivilege.equalsIgnoreAsciiCase("CREATE")) + { + nRights |= Privilege::CREATE; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::CREATE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("ALTER")) + { + nRights |= Privilege::ALTER; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::ALTER; + } + else if (sPrivilege.equalsIgnoreAsciiCase("REFERENCES")) + { + nRights |= Privilege::REFERENCE; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::REFERENCE; + } + else if (sPrivilege.equalsIgnoreAsciiCase("DROP")) + { + nRights |= Privilege::DROP; + if (sGrantable.equalsIgnoreAsciiCase(sYes)) + nRightsWithGrant |= Privilege::DROP; + } + } + ::comphelper::disposeComponent(xRes); +} + +sal_Int32 SAL_CALL OMySQLUser::getGrantablePrivileges(const OUString& objName, sal_Int32 objType) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + + sal_Int32 nRights, nRightsWithGrant; + findPrivilegesAndGrantPrivileges(objName, objType, nRights, nRightsWithGrant); + return nRightsWithGrant; +} + +void SAL_CALL OMySQLUser::grantPrivileges(const OUString& objName, sal_Int32 objType, + sal_Int32 objPrivileges) +{ + if (objType != PrivilegeObject::TABLE) + { + ::connectivity::SharedResources aResources; + const OUString sError(aResources.getResourceString(STR_PRIVILEGE_NOT_GRANTED)); + ::dbtools::throwGenericSQLException(sError, *this); + } // if ( objType != PrivilegeObject::TABLE ) + + ::osl::MutexGuard aGuard(m_aMutex); + + OUString sPrivs = getPrivilegeString(objPrivileges); + if (sPrivs.isEmpty()) + return; + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sGrant + = "GRANT " + sPrivs + " ON " + + ::dbtools::quoteTableName(xMeta, objName, ::dbtools::EComposeRule::InDataManipulation) + + " TO " + m_Name; + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + xStmt->execute(sGrant); + ::comphelper::disposeComponent(xStmt); +} + +void SAL_CALL OMySQLUser::revokePrivileges(const OUString& objName, sal_Int32 objType, + sal_Int32 objPrivileges) +{ + if (objType != PrivilegeObject::TABLE) + { + ::connectivity::SharedResources aResources; + const OUString sError(aResources.getResourceString(STR_PRIVILEGE_NOT_REVOKED)); + ::dbtools::throwGenericSQLException(sError, *this); + } + + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + OUString sPrivs = getPrivilegeString(objPrivileges); + if (sPrivs.isEmpty()) + return; + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + OUString sGrant + = "REVOKE " + sPrivs + " ON " + + ::dbtools::quoteTableName(xMeta, objName, ::dbtools::EComposeRule::InDataManipulation) + + " FROM " + m_Name; + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + xStmt->execute(sGrant); + ::comphelper::disposeComponent(xStmt); +} + +// XUser +void SAL_CALL OMySQLUser::changePassword(const OUString& /*oldPassword*/, + const OUString& newPassword) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE_RBHELPER::rBHelper.bDisposed); + OUString sAlterPwd = "SET PASSWORD FOR " + m_Name + "@\"%\" = PASSWORD('" + newPassword + "')"; + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(sAlterPwd); + ::comphelper::disposeComponent(xStmt); + } +} + +OUString OMySQLUser::getPrivilegeString(sal_Int32 nRights) +{ + OUString sPrivs; + if ((nRights & Privilege::INSERT) == Privilege::INSERT) + sPrivs += "INSERT"; + + if ((nRights & Privilege::DELETE) == Privilege::DELETE) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "DELETE"; + } + + if ((nRights & Privilege::UPDATE) == Privilege::UPDATE) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "UPDATE"; + } + + if ((nRights & Privilege::ALTER) == Privilege::ALTER) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "ALTER"; + } + + if ((nRights & Privilege::SELECT) == Privilege::SELECT) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "SELECT"; + } + + if ((nRights & Privilege::REFERENCE) == Privilege::REFERENCE) + { + if (!sPrivs.isEmpty()) + sPrivs += ","; + sPrivs += "REFERENCES"; + } + + return sPrivs; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YUsers.cxx b/connectivity/source/drivers/mysql_jdbc/YUsers.cxx new file mode 100644 index 000000000..17fc78817 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YUsers.cxx @@ -0,0 +1,95 @@ +/* -*- 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 <mysql/YUsers.hxx> +#include <mysql/YUser.hxx> +#include <connectivity/sdbcx/IRefreshable.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::mysql; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +OUsers::OUsers(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector, + const css::uno::Reference<css::sdbc::XConnection>& _xConnection, + connectivity::sdbcx::IRefreshableUsers* _pParent) + : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + , m_xConnection(_xConnection) + , m_pParent(_pParent) +{ +} + +sdbcx::ObjectType OUsers::createObject(const OUString& _rName) +{ + return new OMySQLUser(m_xConnection, _rName); +} + +void OUsers::impl_refresh() { m_pParent->refreshUsers(); } + +Reference<XPropertySet> OUsers::createDescriptor() +{ + OUserExtend* pNew = new OUserExtend(m_xConnection); + return pNew; +} + +// XAppend +sdbcx::ObjectType OUsers::appendObject(const OUString& _rForName, + const Reference<XPropertySet>& descriptor) +{ + OUString aSql("GRANT USAGE ON * TO "); + OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString(); + aSql += ::dbtools::quoteName(aQuote, _rForName) + " @\"%\" "; + OUString sPassword; + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PASSWORD)) + >>= sPassword; + if (!sPassword.isEmpty()) + { + aSql += " IDENTIFIED BY '" + sPassword + "'"; + } + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + + return createObject(_rForName); +} + +// XDrop +void OUsers::dropObject(sal_Int32 /*_nPos*/, const OUString& _sElementName) +{ + OUString aSql("DROP USER "); + OUString aQuote = m_xConnection->getMetaData()->getIdentifierQuoteString(); + aSql += ::dbtools::quoteName(aQuote, _sElementName); + + Reference<XStatement> xStmt = m_xConnection->createStatement(); + if (xStmt.is()) + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/YViews.cxx b/connectivity/source/drivers/mysql_jdbc/YViews.cxx new file mode 100644 index 000000000..4bdeca959 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/YViews.cxx @@ -0,0 +1,138 @@ +/* -*- 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 <mysql/YViews.hxx> +#include <mysql/YTables.hxx> +#include <mysql/YCatalog.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/sdbcx/VView.hxx> +#include <comphelper/types.hxx> +#include <TConnection.hxx> + +using namespace ::comphelper; + +using namespace ::cppu; +using namespace connectivity; +using namespace connectivity::mysql; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace dbtools; +typedef connectivity::sdbcx::OCollection OCollection_TYPE; + +sdbcx::ObjectType OViews::createObject(const OUString& _rName) +{ + OUString sCatalog, sSchema, sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, _rName, sCatalog, sSchema, sTable, + ::dbtools::EComposeRule::InDataManipulation); + return new ::connectivity::sdbcx::OView(isCaseSensitive(), sTable, m_xMetaData, OUString(), + sSchema, sCatalog); +} + +void OViews::impl_refresh() { static_cast<OMySQLCatalog&>(m_rParent).refreshTables(); } + +void OViews::disposing() +{ + m_xMetaData.clear(); + OCollection::disposing(); +} + +Reference<XPropertySet> OViews::createDescriptor() +{ + Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + connectivity::sdbcx::OView* pNew + = new connectivity::sdbcx::OView(true, xConnection->getMetaData()); + return pNew; +} + +// XAppend +sdbcx::ObjectType OViews::appendObject(const OUString& _rForName, + const Reference<XPropertySet>& descriptor) +{ + createView(descriptor); + return createObject(_rForName); +} + +// XDrop +void OViews::dropObject(sal_Int32 _nPos, const OUString& /*_sElementName*/) +{ + if (m_bInDrop) + return; + + Reference<XInterface> xObject(getObject(_nPos)); + bool bIsNew = connectivity::sdbcx::ODescriptor::isNew(xObject); + if (bIsNew) + return; + + OUString aSql("DROP VIEW"); + + Reference<XPropertySet> xProp(xObject, UNO_QUERY); + aSql += ::dbtools::composeTableName(m_xMetaData, xProp, + ::dbtools::EComposeRule::InTableDefinitions, true); + + Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + Reference<XStatement> xStmt = xConnection->createStatement(); + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); +} + +void OViews::dropByNameImpl(const OUString& elementName) +{ + m_bInDrop = true; + OCollection_TYPE::dropByName(elementName); + m_bInDrop = false; +} + +void OViews::createView(const Reference<XPropertySet>& descriptor) +{ + Reference<XConnection> xConnection = static_cast<OMySQLCatalog&>(m_rParent).getConnection(); + + OUString aSql("CREATE VIEW "); + OUString sCommand; + + aSql += ::dbtools::composeTableName(m_xMetaData, descriptor, + ::dbtools::EComposeRule::InTableDefinitions, true) + + " AS "; + + descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND)) + >>= sCommand; + aSql += sCommand; + + Reference<XStatement> xStmt = xConnection->createStatement(); + if (xStmt.is()) + { + xStmt->execute(aSql); + ::comphelper::disposeComponent(xStmt); + } + + // insert the new view also in the tables collection + OTables* pTables + = static_cast<OTables*>(static_cast<OMySQLCatalog&>(m_rParent).getPrivateTables()); + if (pTables) + { + OUString sName = ::dbtools::composeTableName( + m_xMetaData, descriptor, ::dbtools::EComposeRule::InDataManipulation, false); + pTables->appendNew(sName); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/Yservices.cxx b/connectivity/source/drivers/mysql_jdbc/Yservices.cxx new file mode 100644 index 000000000..a19e489bd --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/Yservices.cxx @@ -0,0 +1,66 @@ +/* -*- 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 <mysql/YDriver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::mysql; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +typedef Reference<XSingleServiceFactory> (*createFactoryFunc)( + const Reference<XMultiServiceFactory>& rServiceManager, const OUString& rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, const Sequence<OUString>& rServiceNames, + rtl_ModuleCount*); + +extern "C" SAL_DLLPUBLIC_EXPORT void* +mysql_jdbc_component_getFactory(const char* pImplementationName, void* pServiceManager, + void* /*pRegistryKey*/) +{ + if (!pServiceManager) + { + return nullptr; + } + + Reference<XSingleServiceFactory> xRet; + const Reference<XMultiServiceFactory> xServiceManager( + static_cast<XMultiServiceFactory*>(pServiceManager)); + const OUString sImplementationName(OUString::createFromAscii(pImplementationName)); + + if (ODriverDelegator::getImplementationName_Static() == sImplementationName) + try + { + xRet = ::cppu::createSingleFactory(xServiceManager, sImplementationName, + ODriverDelegator_CreateInstance, + ODriverDelegator::getSupportedServiceNames_Static()); + } + catch (...) + { + } + + if (xRet.is()) + xRet->acquire(); + + return xRet.get(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component b/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component new file mode 100644 index 000000000..0a1d157e9 --- /dev/null +++ b/connectivity/source/drivers/mysql_jdbc/mysql_jdbc.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="mysql_jdbc" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.drivers.MySQL.Driver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/mysqlc/DataAccess.xcu b/connectivity/source/drivers/mysqlc/DataAccess.xcu new file mode 100644 index 000000000..2b652ec87 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/DataAccess.xcu @@ -0,0 +1,35 @@ +<!-- + * 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 . + --> +<oor:node xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" oor:name="DataAccess" oor:package="org.openoffice.Office"> + <node oor:name="UserDefinedDriverSettings"> + <node oor:name="org.openoffice.comp.connectivity.mysql_native.Driver" oor:op="replace"> + <prop oor:name="DriverName"> + <value>org.openoffice.comp.connectivity.mysql_native.Driver</value> + </prop> + <prop oor:name="DriverPageDisplayName"> + <value>MySQL native driver</value> + </prop> + <prop oor:name="DriverTypeDisplayName"> + <value>MySQL native driver</value> + </prop> + <prop oor:name="DriverDsnPrefix"> + <value>sdbc:mysqlc:</value> + </prop> + </node> + </node> +</oor:node> diff --git a/connectivity/source/drivers/mysqlc/mysqlc.component b/connectivity/source/drivers/mysqlc/mysqlc.component new file mode 100644 index 000000000..e4295110f --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc.component @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> +<component xmlns="http://openoffice.org/2010/uno-components" + loader="com.sun.star.loader.SharedLibrary"> + <implementation name="com.sun.star.comp.sdbc.mysqlc.MysqlCDriver"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx new file mode 100644 index 000000000..600e131b8 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.cxx @@ -0,0 +1,489 @@ +/* -*- 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 "mysqlc_connection.hxx" +#include "mysqlc_databasemetadata.hxx" + +#include "mysqlc_driver.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_general.hxx" + +#include <com/sun/star/beans/NamedValue.hpp> + +#include <osl/diagnose.h> +#include <cppuhelper/supportsservice.hxx> + +using namespace connectivity::mysqlc; + +using namespace com::sun::star::uno; +using namespace com::sun::star::container; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using ::osl::MutexGuard; + +#define MYSQLC_URI_PREFIX "sdbc:mysqlc:" + +namespace +{ +void lcl_executeUpdate(MYSQL* pMySql, const OString& sql) +{ + mysql_real_query(pMySql, sql.getStr(), sql.getLength()); + // TODO handle error +} +} + +OConnection::OConnection(MysqlCDriver& _rDriver) + : OMetaConnection_BASE(m_aMutex) + , m_mysql() + , m_xMetaData(nullptr) + , m_xDriver(&_rDriver) +{ +} + +OConnection::~OConnection() +{ + if (!isClosed()) + { + close(); + } +} + +void OConnection::construct(const OUString& url, const Sequence<PropertyValue>& info) +{ + MutexGuard aGuard(m_aMutex); + + mysql_library_init(0, nullptr, nullptr); + mysql_init(&m_mysql); + + // use TCP as connection + mysql_protocol_type protocol = MYSQL_PROTOCOL_TCP; + mysql_options(&m_mysql, MYSQL_OPT_PROTOCOL, &protocol); + OString charset_name{ "utf8mb4" }; + mysql_options(&m_mysql, MYSQL_SET_CHARSET_NAME, charset_name.getStr()); + + sal_Int32 nIndex; + OUString token; + OUString aHostName("localhost"); + sal_Int32 nPort = 3306; + OUString aDbName; + + m_settings.encoding = MysqlCDriver::getDefaultEncoding(); + + // parse url. Url has the following format: + // external server: sdbc:mysqlc:[hostname]:[port]/[dbname] + + if (url.startsWith(MYSQLC_URI_PREFIX)) + { + nIndex = 12; + } + else + { + // sdbc:mysql:mysqlc:[hostname]:[port]/[dbname] + nIndex = 18; + } + + token = url.getToken(0, '/', nIndex); + if (!token.isEmpty()) + { + sal_Int32 nIndex1 = 0; + OUString hostandport = token.getToken(0, ':', nIndex1); + if (!hostandport.isEmpty()) + { + aHostName = hostandport; + hostandport = token.getToken(0, ':', nIndex1); + if (!hostandport.isEmpty() && nIndex1) + { + nPort = hostandport.toInt32(); + } + token = url.getToken(0, '/', nIndex); + if (!token.isEmpty() && nIndex) + { + aDbName = token; + } + } + } + + // get user and password for mysql connection + const PropertyValue* pIter = info.getConstArray(); + const PropertyValue* pEnd = pIter + info.getLength(); + OUString aUser, aPass, sUnixSocket, sNamedPipe; + bool unixSocketPassed = false; + bool namedPipePassed = false; + + m_settings.connectionURL = url; + for (; pIter != pEnd; ++pIter) + { + if (pIter->Name == "user") + { + OSL_VERIFY(pIter->Value >>= aUser); + } + else if (pIter->Name == "password") + { + OSL_VERIFY(pIter->Value >>= aPass); + } + else if (pIter->Name == "LocalSocket") + { + OSL_VERIFY(pIter->Value >>= sUnixSocket); + unixSocketPassed = !sUnixSocket.isEmpty(); + } + else if (pIter->Name == "NamedPipe") + { + OSL_VERIFY(pIter->Value >>= sNamedPipe); + namedPipePassed = !sNamedPipe.isEmpty(); + } + else if (pIter->Name == "PublicConnectionURL") + { + OSL_VERIFY(pIter->Value >>= m_settings.connectionURL); + } + else if (pIter->Name == "NewURL") + { // legacy name for "PublicConnectionURL" + OSL_VERIFY(pIter->Value >>= m_settings.connectionURL); + } + } + + OString host_str = OUStringToOString(aHostName, m_settings.encoding); + OString user_str = OUStringToOString(aUser, m_settings.encoding); + OString pass_str = OUStringToOString(aPass, m_settings.encoding); + OString schema_str = OUStringToOString(aDbName, m_settings.encoding); + OString socket_str; + if (unixSocketPassed) + { + socket_str = OUStringToOString(sUnixSocket, m_settings.encoding); + } + else if (namedPipePassed) + { + socket_str = OUStringToOString(sNamedPipe, m_settings.encoding); + } + + // flags can also be passed as last parameter + if (!mysql_real_connect(&m_mysql, host_str.getStr(), user_str.getStr(), pass_str.getStr(), + schema_str.getStr(), nPort, socket_str.getStr(), + CLIENT_MULTI_STATEMENTS)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this, + getConnectionEncoding()); + + // Check if the server is 4.1 or above + if (getMysqlVersion() < 40100) + { + throw SQLException("MariaDB LibreOffice Connector requires MySQL Server 4.1 or above", + *this, OUString(), 0, Any()); + } + + lcl_executeUpdate(&m_mysql, + OString{ "SET session sql_mode='ANSI_QUOTES,NO_AUTO_VALUE_ON_ZERO'" }); + lcl_executeUpdate(&m_mysql, OString{ "SET NAMES utf8mb4" }); +} + +OUString OConnection::getImplementationName() +{ + return "com.sun.star.sdbc.drivers.mysqlc.OConnection"; +} + +css::uno::Sequence<OUString> OConnection::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.Connection" }; +} + +sal_Bool OConnection::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Reference<XStatement> SAL_CALL OConnection::createStatement() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // create a statement + // the statement can only be executed once + Reference<XStatement> xReturn = new OStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + + return xReturn; +} + +Reference<XPreparedStatement> SAL_CALL OConnection::prepareStatement(const OUString& _sSql) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + const OString sSqlStatement + = OUStringToOString(_sSql, getConnectionEncoding()); // FIXME transform statement ? + + MYSQL_STMT* pStmt = mysql_stmt_init(&m_mysql); + mysql_stmt_prepare(pStmt, sSqlStatement.getStr(), sSqlStatement.getLength()); + + unsigned int nErrorNum = mysql_errno(&m_mysql); + if (nErrorNum != 0) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(&m_mysql), + mysql_sqlstate(&m_mysql), nErrorNum, *this, + getConnectionEncoding()); + + Reference<XPreparedStatement> xStatement = new OPreparedStatement(this, pStmt); + m_aStatements.push_back(WeakReferenceHelper(xStatement)); + return xStatement; +} + +Reference<XPreparedStatement> SAL_CALL OConnection::prepareCall(const OUString& /*_sSql*/) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OConnection::prepareCall", *this); + return Reference<XPreparedStatement>(); +} + +OUString SAL_CALL OConnection::nativeSQL(const OUString& /*_sSql*/) +{ + MutexGuard aGuard(m_aMutex); + + // const OUString sSqlStatement = transFormPreparedStatement( _sSql ); + // TODO + return OUString(); +} + +void SAL_CALL OConnection::setAutoCommit(sal_Bool autoCommit) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + if (!mysql_autocommit(&m_mysql, autoCommit)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this, + getConnectionEncoding()); +} + +sal_Bool SAL_CALL OConnection::getAutoCommit() +{ + // you have to distinguish which if you are in autocommit mode or not + // at normal case true should be fine here + + // TODO use SELECT @@autocommit query for that + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + return false; +} + +void SAL_CALL OConnection::commit() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + if (!mysql_commit(&m_mysql)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this, + getConnectionEncoding()); +} + +void SAL_CALL OConnection::rollback() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + if (!mysql_rollback(&m_mysql)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(&m_mysql), mysql_sqlstate(&m_mysql), mysql_errno(&m_mysql), *this, + getConnectionEncoding()); +} + +sal_Bool SAL_CALL OConnection::isClosed() +{ + MutexGuard aGuard(m_aMutex); + + // just simple -> we are close when we are disposed that means someone called dispose(); (XComponent) + return OConnection_BASE::rBHelper.bDisposed; +} + +Reference<XDatabaseMetaData> SAL_CALL OConnection::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference<XDatabaseMetaData> xMetaData = m_xMetaData; + if (!xMetaData.is()) + { + xMetaData = new ODatabaseMetaData(*this, &m_mysql); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +void SAL_CALL OConnection::setReadOnly(sal_Bool readOnly) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + m_settings.readOnly = readOnly; +} + +sal_Bool SAL_CALL OConnection::isReadOnly() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // return if your connection to readonly + return m_settings.readOnly; +} + +void SAL_CALL OConnection::setCatalog(const OUString& /*catalog*/) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // TODO How? +} + +OUString SAL_CALL OConnection::getCatalog() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // TODO How? + return OUString{}; +} + +void SAL_CALL OConnection::setTransactionIsolation(sal_Int32 /*level*/) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + // TODO +} + +sal_Int32 SAL_CALL OConnection::getTransactionIsolation() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + return 0; // TODO +} + +Reference<XNameAccess> SAL_CALL OConnection::getTypeMap() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference<XNameAccess> t = m_typeMap; + return t; +} + +void SAL_CALL OConnection::setTypeMap(const Reference<XNameAccess>& typeMap) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + m_typeMap = typeMap; +} + +// XCloseable +void SAL_CALL OConnection::close() +{ + /* + we need block, because the mutex is a local variable, + which will guard the block + */ + { + // we just dispose us + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + } + mysql_close(&m_mysql); + mysql_library_end(); + dispose(); +} + +// XWarningsSupplier +Any SAL_CALL OConnection::getWarnings() +{ + Any x; + // when you collected some warnings -> return it + return x; +} + +void SAL_CALL OConnection::clearWarnings() +{ + // you should clear your collected warnings here# +} + +void OConnection::disposing() +{ + // we noticed that we should be destroyed in near future so we have to dispose our statements + MutexGuard aGuard(m_aMutex); + + for (auto const& statement : m_aStatements) + { + Reference<XComponent> xComp(statement.get(), UNO_QUERY); + if (xComp.is()) + { + xComp->dispose(); + } + } + m_aStatements.clear(); + + m_xMetaData = WeakReference<XDatabaseMetaData>(); + + OConnection_BASE::disposing(); +} + +sal_Int32 OConnection::getMysqlVersion() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + unsigned long version = mysql_get_server_version(&m_mysql); + return static_cast<sal_Int32>(version); +} + +OUString OConnection::transFormPreparedStatement(const OUString& _sSQL) +{ + OUString sSqlStatement = _sSQL; + if (!m_xParameterSubstitution.is()) + { + try + { + Sequence<Any> aArgs(1); + Reference<XConnection> xCon = this; + aArgs[0] <<= NamedValue("ActiveConnection", makeAny(xCon)); + + m_xParameterSubstitution.set( + m_xDriver->getFactory()->createInstanceWithArguments( + "org.openoffice.comp.helper.ParameterSubstitution", aArgs), + UNO_QUERY); + } + catch (const Exception&) + { + } + } + if (m_xParameterSubstitution.is()) + { + try + { + sSqlStatement = m_xParameterSubstitution->substituteVariables(sSqlStatement, true); + } + catch (const Exception&) + { + } + } + return sSqlStatement; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx b/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx new file mode 100644 index 000000000..283b1d964 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_connection.hxx @@ -0,0 +1,187 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_CONNECTION_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_CONNECTION_HXX + +#include <memory> +#include "mysqlc_subcomponent.hxx" +#include "mysqlc_types.hxx" + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/util/XStringSubstitution.hpp> + +#include <cppuhelper/compbase3.hxx> +#include <cppuhelper/weakref.hxx> +#include <rtl/string.hxx> +#include <rtl/ref.hxx> + +#include <mysql.h> + +#include <map> + +namespace sql +{ +class SQLException; +} + +namespace connectivity +{ +class OMetaConnection; +class ODatabaseMetaData; + +namespace mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::sdbc::SQLWarning; +using ::com::sun::star::uno::RuntimeException; + +typedef ::cppu::WeakComponentImplHelper3<css::sdbc::XConnection, css::sdbc::XWarningsSupplier, + css::lang::XServiceInfo> + OMetaConnection_BASE; + +struct ConnectionSettings +{ + rtl_TextEncoding encoding; + OUString connectionURL; + bool readOnly; + ConnectionSettings() + : encoding(RTL_TEXTENCODING_DONTKNOW) + , readOnly(false) + { + } +}; + +class MysqlCDriver; + +typedef OMetaConnection_BASE OConnection_BASE; + +typedef std::vector<css::uno::WeakReferenceHelper> OWeakRefArray; + +class OConnection final : public OBase_Mutex, public OConnection_BASE +{ +private: + MYSQL m_mysql; + ConnectionSettings m_settings; + css::uno::Reference<css::container::XNameAccess> m_typeMap; + css::uno::Reference<css::util::XStringSubstitution> m_xParameterSubstitution; + + // Data attributes + + css::uno::WeakReference<css::sdbc::XDatabaseMetaData> m_xMetaData; + + OWeakRefArray m_aStatements; // vector containing a list + // of all the Statement objects + // for this Connection + + rtl::Reference<MysqlCDriver> m_xDriver; // Pointer to the owning driver object +public: + MYSQL* getMysqlConnection() { return &m_mysql; } + + /// @throws SQLException + /// @throws RuntimeException + sal_Int32 getMysqlVersion(); + + /// @throws SQLException + void construct(const OUString& url, const css::uno::Sequence<css::beans::PropertyValue>& info); + + OConnection(MysqlCDriver& _rDriver); + virtual ~OConnection() override; + + rtl_TextEncoding getConnectionEncoding() const { return m_settings.encoding; } + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XConnection + css::uno::Reference<css::sdbc::XStatement> SAL_CALL createStatement() override; + + css::uno::Reference<css::sdbc::XPreparedStatement> + SAL_CALL prepareStatement(const OUString& sql) override; + + css::uno::Reference<css::sdbc::XPreparedStatement> + SAL_CALL prepareCall(const OUString& sql) override; + + OUString SAL_CALL nativeSQL(const OUString& sql) override; + + void SAL_CALL setAutoCommit(sal_Bool autoCommit) override; + + sal_Bool SAL_CALL getAutoCommit() override; + + void SAL_CALL commit() override; + + void SAL_CALL rollback() override; + + sal_Bool SAL_CALL isClosed() override; + + css::uno::Reference<css::sdbc::XDatabaseMetaData> SAL_CALL getMetaData() override; + + void SAL_CALL setReadOnly(sal_Bool readOnly) override; + + sal_Bool SAL_CALL isReadOnly() override; + + void SAL_CALL setCatalog(const OUString& catalog) override; + + OUString SAL_CALL getCatalog() override; + + void SAL_CALL setTransactionIsolation(sal_Int32 level) override; + + sal_Int32 SAL_CALL getTransactionIsolation() override; + + css::uno::Reference<css::container::XNameAccess> SAL_CALL getTypeMap() override; + + void SAL_CALL + setTypeMap(const css::uno::Reference<css::container::XNameAccess>& typeMap) override; + // XCloseable + void SAL_CALL close() override; + // XWarningsSupplier + css::uno::Any SAL_CALL getWarnings() override; + void SAL_CALL clearWarnings() override; + + // TODO: Not used + //sal_Int32 sdbcColumnType(OUString typeName); + const ConnectionSettings& getConnectionSettings() const { return m_settings; } + OUString transFormPreparedStatement(const OUString& _sSQL); + + const MysqlCDriver& getDriver() const { return *m_xDriver; } + +}; /* OConnection */ +// TODO: Not used. +//inline OUString getPattern(OUString p) { return (p.getLength()) ? p : ASC2OU("%"); } +} /* mysqlc */ +} /* connectivity */ +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_CONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx new file mode 100644 index 000000000..a30e5d618 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.cxx @@ -0,0 +1,1076 @@ +/* -*- 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 "mysqlc_databasemetadata.hxx" +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <com/sun/star/sdbc/Deferrability.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <comphelper/sequence.hxx> + +#include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> +#include "mysqlc_general.hxx" +#include "mysqlc_driver.hxx" +#include "mysqlc_preparedstatement.hxx" + +using namespace connectivity::mysqlc; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +static std::string wild("%"); + +static void lcl_setRows_throw(const Reference<XResultSet>& _xResultSet, sal_Int32 _nType, + const std::vector<std::vector<Any>>& _rRows) +{ + Reference<XInitialization> xIni(_xResultSet, UNO_QUERY); + Sequence<Any> aArgs(2); + aArgs[0] <<= _nType; + + Sequence<Sequence<Any>> aRows(_rRows.size()); + + Sequence<Any>* pRowsIter = aRows.getArray(); + for (const auto& rRow : _rRows) + { + if (!rRow.empty()) + { + (*pRowsIter) = comphelper::containerToSequence(rRow); + } + ++pRowsIter; + } + aArgs[1] <<= aRows; + xIni->initialize(aArgs); +} + +ODatabaseMetaData::ODatabaseMetaData(OConnection& _rCon, MYSQL* pMySql) + : m_rConnection(_rCon) + , m_pMySql(pMySql) +{ +} + +ODatabaseMetaData::~ODatabaseMetaData() {} + +OUString SAL_CALL ODatabaseMetaData::getCatalogSeparator() { return OUString(); } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength() { return 16777208L; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize() +{ + return 2147483647L - 8; // Max buffer size - HEADER +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength() { return 32; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength() { return 16777208; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex() { return 16; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + // TODO + // SELECT @@max_connections + return 100; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable() { return 512; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + // TODO + // "SHOW VARIABLES LIKE 'max_allowed_packet'" + return 32767; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTablesInSelect() { return 256; } + +sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + // TODO + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + //TODO; + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseQuotedIdentifiers() +{ + SAL_WARN("connectivity.mysqlc", "method not implemented"); + // TODO + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithAddColumn() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsAlterTableWithDropColumn() { return true; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength() { return 256; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns() { return true; } + +OUString SAL_CALL ODatabaseMetaData::getCatalogTerm() { return "n/a"; } + +OUString SAL_CALL ODatabaseMetaData::getIdentifierQuoteString() { return "\""; } + +OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters() { return "#@"; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::isCatalogAtStart() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions() +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel(sal_Int32 /*level*/) +{ + return true; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInDataManipulation() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInTableDefinitions() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInTableDefinitions() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInDataManipulation() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins() { return true; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatements() { return 0; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength() { return 64; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures() +{ + return m_rConnection.getMysqlVersion() >= 50000; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate() +{ + return m_rConnection.getMysqlVersion() >= 40000; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert(sal_Int32 /*fromType*/, sal_Int32 /*toType*/) +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion() +{ + return m_rConnection.getMysqlVersion() >= 40000; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll() +{ + return m_rConnection.getMysqlVersion() >= 40000; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseQuotedIdentifiers() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart() +{ + return m_rConnection.getMysqlVersion() > 40001 && m_rConnection.getMysqlVersion() < 40011; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow() { return !nullsAreSortedHigh(); } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls() +{ + return m_rConnection.getMysqlVersion() >= 32200; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions() +{ + return m_rConnection.getMysqlVersion() >= 32200; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds() +{ + return m_rConnection.getMysqlVersion() >= 40100; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL() { return false; } + +OUString SAL_CALL ODatabaseMetaData::getURL() +{ + return m_rConnection.getConnectionSettings().connectionURL; +} + +OUString SAL_CALL ODatabaseMetaData::getUserName() +{ + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery("select user()"); + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + (void)rs->next(); // the first and only result + // e.g. root@localhost + OUString userWithConnection = xRow->getString(1); + sal_Int32 nIndexOfAt = userWithConnection.indexOf("@"); + if (nIndexOfAt > 0) + { + OUString user = userWithConnection.copy(0, nIndexOfAt); + return user; + } + return userWithConnection; +} + +OUString SAL_CALL ODatabaseMetaData::getDriverName() { return "MySQL Connector/OO.org"; } + +OUString SAL_CALL ODatabaseMetaData::getDriverVersion() { return "0.9.2"; } + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion() +{ + return OStringToOUString(mysql_get_server_info(m_pMySql), + m_rConnection.getConnectionEncoding()); +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName() { return "MySQL"; } + +OUString SAL_CALL ODatabaseMetaData::getProcedureTerm() { return "procedure"; } + +OUString SAL_CALL ODatabaseMetaData::getSchemaTerm() { return "database"; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return MARIADBC_VERSION_MAJOR; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation() +{ + return TransactionIsolation::REPEATABLE_READ; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion() +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + return MARIADBC_VERSION_MINOR; +} + +OUString SAL_CALL ODatabaseMetaData::getSQLKeywords() +{ + return "ACCESSIBLE, ADD, ALL," + "ALTER, ANALYZE, AND, AS, ASC, ASENSITIVE, BEFORE," + "BETWEEN, BIGINT, BINARY, BLOB, BOTH, BY, CALL," + "CASCADE, CASE, CHANGE, CHAR, CHARACTER, CHECK," + "COLLATE, COLUMN, CONDITION, CONNECTION, CONSTRAINT," + "CONTINUE, CONVERT, CREATE, CROSS, CURRENT_DATE," + "CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR," + "DATABASE, DATABASES, DAY_HOUR, DAY_MICROSECOND," + "DAY_MINUTE, DAY_SECOND, DEC, DECIMAL, DECLARE," + "DEFAULT, DELAYED, DELETE, DESC, DESCRIBE," + "DETERMINISTIC, DISTINCT, DISTINCTROW, DIV, DOUBLE," + "DROP, DUAL, EACH, ELSE, ELSEIF, ENCLOSED," + "ESCAPED, EXISTS, EXIT, EXPLAIN, FALSE, FETCH," + "FLOAT, FLOAT4, FLOAT8, FOR, FORCE, FOREIGN, FROM," + "FULLTEXT, GRANT, GROUP, HAVING, HIGH_PRIORITY," + "HOUR_MICROSECOND, HOUR_MINUTE, HOUR_SECOND, IF," + "IGNORE, IN, INDEX, INFILE, INNER, INOUT," + "INSENSITIVE, INSERT, INT, INT1, INT2, INT3, INT4," + "INT8, INTEGER, INTERVAL, INTO, IS, ITERATE, JOIN," + "KEY, KEYS, KILL, LEADING, LEAVE, LEFT, LIKE," + "LOCALTIMESTAMP, LOCK, LONG, LONGBLOB, LONGTEXT," + "LOOP, LOW_PRIORITY, MATCH, MEDIUMBLOB, MEDIUMINT," + "MEDIUMTEXT, MIDDLEINT, MINUTE_MICROSECOND," + "MINUTE_SECOND, MOD, MODIFIES, NATURAL, NOT," + "NO_WRITE_TO_BINLOG, NULL, NUMERIC, ON, OPTIMIZE," + "OPTION, OPTIONALLY, OR, ORDER, OUT, OUTER," + "OUTFILE, PRECISION, PRIMARY, PROCEDURE, PURGE," + "RANGE, READ, READS, READ_ONLY, READ_WRITE, REAL," + "REFERENCES, REGEXP, RELEASE, RENAME, REPEAT," + "REPLACE, REQUIRE, RESTRICT, RETURN, REVOKE, RIGHT," + "RLIKE, SCHEMA, SCHEMAS, SECOND_MICROSECOND, SELECT," + "SENSITIVE, SEPARATOR, SET, SHOW, SMALLINT, SPATIAL," + "SPECIFIC, SQL, SQLEXCEPTION, SQLSTATE, SQLWARNING," + "SQL_BIG_RESULT, SQL_CALC_FOUND_ROWS, SQL_SMALL_RESULT," + "SSL, STARTING, STRAIGHT_JOIN, TABLE, TERMINATED," + "THEN, TINYBLOB, TINYINT, TINYTEXT, TO, TRAILING," + "TRIGGER, TRUE, UNDO, UNION, UNIQUE, UNLOCK," + "UNSIGNED, UPDATE, USAGE, USE, USING, UTC_DATE," + "UTC_TIME, UTC_TIMESTAMP, VALUES, VARBINARY, VARCHAR," + "VARCHARACTER, VARYING, WHEN, WHERE, WHILE, WITH," + "WRITE, X509, XOR, YEAR_MONTH, ZEROFILL" + "GENERAL, IGNORE_SERVER_IDS, MASTER_HEARTBEAT_PERIOD," + "MAXVALUE, RESIGNAL, SIGNAL, SLOW"; +} + +OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape() { return "\\"; } + +OUString SAL_CALL ODatabaseMetaData::getStringFunctions() +{ + return "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT," + "CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT," + "INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD," + "LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION," + "QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX," + "SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING," + "SUBSTRING_INDEX,TRIM,UCASE,UPPER"; +} + +OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions() +{ + return "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME," + "MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD," + "PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT," + "CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE," + "CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME," + "SEC_TO_TIME,TIME_TO_SEC"; +} + +OUString SAL_CALL ODatabaseMetaData::getSystemFunctions() +{ + return "DATABASE,USER,SYSTEM_USER," + "SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION"; +} + +OUString SAL_CALL ODatabaseMetaData::getNumericFunctions() +{ + return "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS," + "COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW," + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE"; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar() { return true; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins() { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins() { return true; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy() { return 64; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect() { return 256; } + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength() { return 16; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType(sal_Int32 setType) +{ + return setType == ResultSetType::SCROLL_SENSITIVE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency(sal_Int32 /*setType*/, + sal_Int32 /*concurrency*/) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible(sal_Int32 /*setType*/) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible(sal_Int32 /*setType*/) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible(sal_Int32 /*setType*/) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected(sal_Int32 /*setType*/) { return false; } + +sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates() { return false; } + +Reference<XConnection> SAL_CALL ODatabaseMetaData::getConnection() { return &m_rConnection; } + +/* + Here follow all methods which return(a resultset + the first methods is an example implementation how to use this resultset + of course you could implement it on your and you should do this because + the general way is more memory expensive +*/ + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTableTypes() +{ + const char* const table_types[] = { "TABLE", "VIEW" }; + sal_Int32 const requiredVersion[] = { 0, 50000 }; + + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + rtl_TextEncoding encoding = m_rConnection.getConnectionEncoding(); + + for (sal_uInt32 i = 0; i < 2; i++) + { + if (m_rConnection.getMysqlVersion() >= requiredVersion[i]) + { + std::vector<Any> aRow{ Any() }; + aRow.push_back(makeAny(mysqlc_sdbc_driver::convert(table_types[i], encoding))); + rRows.push_back(aRow); + } + } + lcl_setRows_throw(xResultSet, 5, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTypeInfo() +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + + std::vector<std::vector<Any>> rRows; + + rtl_TextEncoding encoding = m_rConnection.getConnectionEncoding(); + unsigned int i = 0; + while (mysqlc_types[i].typeName) + { + std::vector<Any> aRow{ Any() }; + + aRow.push_back(makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].typeName, encoding))); + aRow.push_back(makeAny(mysqlc_types[i].dataType)); + aRow.push_back(makeAny(mysqlc_types[i].precision)); + aRow.push_back( + makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].literalPrefix, encoding))); + aRow.push_back( + makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].literalSuffix, encoding))); + aRow.push_back( + makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].createParams, encoding))); + aRow.push_back(makeAny(mysqlc_types[i].nullable)); + aRow.push_back(makeAny(mysqlc_types[i].caseSensitive)); + aRow.push_back(makeAny(mysqlc_types[i].searchable)); + aRow.push_back(makeAny(mysqlc_types[i].isUnsigned)); + aRow.push_back(makeAny(mysqlc_types[i].fixedPrecScale)); + aRow.push_back(makeAny(mysqlc_types[i].autoIncrement)); + aRow.push_back( + makeAny(mysqlc_sdbc_driver::convert(mysqlc_types[i].localTypeName, encoding))); + aRow.push_back(makeAny(mysqlc_types[i].minScale)); + aRow.push_back(makeAny(mysqlc_types[i].maxScale)); + aRow.push_back(makeAny(sal_Int32(0))); + aRow.push_back(makeAny(sal_Int32(0))); + aRow.push_back(makeAny(sal_Int32(10))); + + rRows.push_back(aRow); + i++; + } + + lcl_setRows_throw(xResultSet, 14, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getCatalogs() +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getSchemas() +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + + OUString sSql + = m_rConnection.getMysqlVersion() > 49999 + ? OUString{ "SELECT SCHEMA_NAME AS TABLE_SCHEM, CATALOG_NAME AS TABLE_CATALOG " + "FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY SCHEMA_NAME" } + : OUString{ "SHOW DATABASES" }; + + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XInterface> executed = statement->executeQuery(sSql); + Reference<XResultSet> rs(executed, UNO_QUERY_THROW); + Reference<XResultSetMetaDataSupplier> supp(executed, UNO_QUERY_THROW); + Reference<XResultSetMetaData> rs_meta = supp->getMetaData(); + + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + sal_uInt32 columns = rs_meta->getColumnCount(); + while (rs->next()) + { + std::vector<Any> aRow{ Any() }; + bool informationSchema = false; + for (sal_uInt32 i = 1; i <= columns; i++) + { + OUString columnStringValue = xRow->getString(i); + if (i == 1) + { // TABLE_SCHEM + informationSchema = columnStringValue.equalsIgnoreAsciiCase("information_schema"); + } + aRow.push_back(makeAny(columnStringValue)); + } + if (!informationSchema) + { + rRows.push_back(aRow); + } + } + + lcl_setRows_throw(xResultSet, 1, rRows); + return xResultSet; +} + +Reference<XResultSet> + SAL_CALL ODatabaseMetaData::getColumnPrivileges(const Any& /*catalog*/, const OUString& schema, + const OUString& table, + const OUString& columnNamePattern) +{ + OUString query("SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA AS " + "TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, NULL AS GRANTOR, " + "GRANTEE, PRIVILEGE_TYPE AS PRIVILEGE, IS_GRANTABLE FROM " + "INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE TABLE_SCHEMA LIKE " + "'?' AND TABLE_NAME='?' AND COLUMN_NAME LIKE '?' ORDER BY " + "COLUMN_NAME, PRIVILEGE_TYPE"); + + query = query.replaceFirst("?", schema); + query = query.replaceFirst("?", table); + query = query.replaceFirst("?", columnNamePattern); + + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query); + return rs; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getColumns(const Any& /*catalog*/, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern) +{ + OUStringBuffer queryBuf("SELECT TABLE_CATALOG, " // 1 + "TABLE_SCHEMA, " // 2 + "TABLE_NAME, " // 3 + "COLUMN_NAME, " // 4 + "DATA_TYPE, " // 5 + // TYPE_NAME missing + "CHARACTER_MAXIMUM_LENGTH, " // 6 + "NUMERIC_PRECISION, " // 7 + // buffer length missing + "NUMERIC_SCALE AS DECIMAL_DIGITS, " // 8 + // NUM_PREC_RADIX missing + // NULLABLE missing + "COLUMN_COMMENT AS REMARKS, " // 9 + "COLUMN_DEFAULT AS COLUMN_DEF," // 10 + "CHARACTER_OCTET_LENGTH, " // 11 + "ORDINAL_POSITION, " // 12 + "IS_NULLABLE, " // 13 + "COLUMN_TYPE " // 14 + "FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE (1 = 1) "); + if (!tableNamePattern.isEmpty()) + { + OUString sAppend; + if (tableNamePattern.match("%")) + sAppend = "AND TABLE_NAME LIKE '%' "; + else + sAppend = "AND TABLE_NAME = '%' "; + queryBuf.append(sAppend.replaceAll("%", tableNamePattern)); + } + if (!schemaPattern.isEmpty()) + { + OUString sAppend; + if (schemaPattern.match("%")) + sAppend = "AND TABLE_SCHEMA LIKE '%' "; + else + sAppend = "AND TABLE_SCHEMA = '%' "; + queryBuf.append(sAppend.replaceAll("%", schemaPattern)); + } + if (!columnNamePattern.isEmpty()) + { + OUString sAppend; + if (columnNamePattern.match("%")) + sAppend = "AND COLUMN_NAME LIKE '%' "; + else + sAppend = "AND COLUMN_NAME = '%' "; + queryBuf.append(sAppend.replaceAll("%", columnNamePattern)); + } + + OUString query = queryBuf.makeStringAndClear(); + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query.getStr()); + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> aRows; + while (rs->next()) + { + std::vector<Any> aRow{ Any() }; // 0. element is unused + + // catalog name + aRow.push_back(makeAny(xRow->getString(1))); + // schema name + aRow.push_back(makeAny(xRow->getString(2))); + // table name + aRow.push_back(makeAny(xRow->getString(3))); + // column name + aRow.push_back(makeAny(xRow->getString(4))); + // data type + OUString sDataType = xRow->getString(5); + aRow.push_back(makeAny(mysqlc_sdbc_driver::mysqlStrToOOOType(sDataType))); + // type name + aRow.push_back(makeAny(sDataType)); // TODO + // column size + sal_Int32 nColumnSize = 0; + OUString sColumnType = xRow->getString(14); + sal_Int32 nCharMaxLen = xRow->getShort(6); + bool bIsCharMax = !xRow->wasNull(); + if (sDataType.equalsIgnoreAsciiCase("year")) + nColumnSize = sColumnType.copy(6, 1).toInt32(); // 'year(' length is 5 + else if (sDataType.equalsIgnoreAsciiCase("date")) + nColumnSize = 10; + else if (sDataType.equalsIgnoreAsciiCase("time")) + nColumnSize = 8; + else if (sDataType.equalsIgnoreAsciiCase("datetime") + || sDataType.equalsIgnoreAsciiCase("timestamp")) + nColumnSize = 19; + else if (!bIsCharMax) + nColumnSize = xRow->getShort(7); // numeric precision + else + nColumnSize = nCharMaxLen; + aRow.push_back(makeAny(nColumnSize)); + aRow.push_back(Any()); // buffer length - unused + // decimal digits (scale) + aRow.push_back(makeAny(xRow->getShort(8))); + // num_prec_radix + aRow.push_back(makeAny(sal_Int32(10))); + // nullable + OUString sIsNullable = xRow->getString(13); + if (xRow->wasNull()) + aRow.push_back(makeAny(ColumnValue::NULLABLE_UNKNOWN)); + else if (sIsNullable.equalsIgnoreAsciiCase("YES")) + aRow.push_back(makeAny(ColumnValue::NULLABLE)); + else + aRow.push_back(makeAny(ColumnValue::NO_NULLS)); + // remarks + aRow.push_back(makeAny(xRow->getString(9))); + // default + aRow.push_back(makeAny(xRow->getString(10))); + + aRow.push_back(Any{}); // sql_data_type - unused + aRow.push_back(Any{}); // sql_datetime_sub - unused + + // character octet length + aRow.push_back(makeAny(xRow->getString(11))); + // ordinal position + aRow.push_back(makeAny(xRow->getString(12))); + // is nullable + aRow.push_back(makeAny(sIsNullable)); + aRows.push_back(aRow); + } + lcl_setRows_throw(xResultSet, 1, aRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTables(const Any& /*catalog*/, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const Sequence<OUString>& types) +{ + OUStringBuffer buffer{ + "SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA AS TABLE_SCHEM, TABLE_NAME," + "IF(STRCMP(TABLE_TYPE,'BASE TABLE'), TABLE_TYPE, 'TABLE') AS TABLE_TYPE, TABLE_COMMENT AS " + "REMARKS " + "FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA LIKE '?' AND TABLE_NAME LIKE '?' " + }; + + if (types.getLength() == 1) + { + buffer.append("AND TABLE_TYPE LIKE '"); + buffer.append(types[0]); + buffer.append("'"); + } + else if (types.getLength() > 1) + { + buffer.append("AND (TABLE_TYPE LIKE '"); + buffer.append(types[0]); + buffer.append("'"); + for (sal_Int32 i = 1; i < types.getLength(); ++i) + { + buffer.append(" OR TABLE_TYPE LIKE '"); + buffer.append(types[i]); + buffer.append("'"); + } + buffer.append(")"); + } + + buffer.append(" ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME"); + OUString query = buffer.makeStringAndClear(); + + // TODO use prepared stmt instead + // TODO escape schema, table name ? + query = query.replaceFirst("?", schemaPattern); + query = query.replaceFirst("?", tableNamePattern); + + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query); + return rs; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getProcedureColumns( + const Any& /* catalog */, const OUString& /* schemaPattern */, + const OUString& /* procedureNamePattern */, const OUString& /* columnNamePattern */) +{ + // Currently there is no information available + return nullptr; +} + +Reference<XResultSet> + SAL_CALL ODatabaseMetaData::getProcedures(const Any& /*catalog*/, + const OUString& /*schemaPattern*/, + const OUString& /*procedureNamePattern*/) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO IMPL + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 7, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getVersionColumns(const Any& /* catalog */, + const OUString& /* schema */, + const OUString& /* table */) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + lcl_setRows_throw(xResultSet, 16, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getExportedKeys(const Any& /*catalog */, + const OUString& /*schema */, + const OUString& /*table */) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO implement + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 8, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getImportedKeys(const Any& /*catalog*/, + const OUString& schema, + const OUString& table) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + + OUString query("SELECT refi.CONSTRAINT_CATALOG," // 1: foreign catalog + " k.COLUMN_NAME," // 2: foreign column name + " refi.UNIQUE_CONSTRAINT_CATALOG," // 3: primary catalog FIXME + " k.REFERENCED_TABLE_SCHEMA," // 4: primary schema + " refi.REFERENCED_TABLE_NAME," // 5: primary table name + " k.REFERENCED_COLUMN_NAME," // 6: primary column name + " refi.UPDATE_RULE, refi.DELETE_RULE," // 7,8: update, delete rule + " refi.CONSTRAINT_NAME, " // 9: name of constraint itself + " refi.TABLE_NAME, " // 10: foreign table name + " refi.CONSTRAINT_SCHEMA " // 11: foreign schema name FIXME + " FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as refi" + " INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as k ON k.CONSTRAINT_NAME = " + "refi.CONSTRAINT_NAME " + " and k.TABLE_NAME = refi.TABLE_NAME " + " WHERE k.REFERENCED_TABLE_SCHEMA LIKE " + "'?' AND refi.TABLE_NAME='?'"); + query = query.replaceFirst("?", schema); // TODO what if schema is NULL? + query = query.replaceFirst("?", table); + + std::vector<std::vector<Any>> aRows; + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query.getStr()); + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + + while (rs->next()) + { + std::vector<Any> aRow{ Any() }; // 0. element is unused + + // primary key catalog + aRow.push_back(makeAny(xRow->getString(3))); + // primary key schema + aRow.push_back(makeAny(xRow->getString(4))); + // primary key table + aRow.push_back(makeAny(xRow->getString(5))); + // primary column name + aRow.push_back(makeAny(xRow->getString(6))); + + // fk table catalog + aRow.push_back(makeAny(xRow->getString(1))); + // fk schema + aRow.push_back(makeAny(xRow->getString(11))); + // fk table + aRow.push_back(makeAny(xRow->getString(10))); + // fk column name + aRow.push_back(makeAny(xRow->getString(2))); + // KEY_SEQ + aRow.push_back(makeAny(sal_Int32{ 0 })); // TODO + // update rule + aRow.push_back(makeAny(xRow->getShort(7))); + // delete rule + aRow.push_back(makeAny(xRow->getShort(8))); + // foreign key name + aRow.push_back(makeAny(xRow->getString(9))); + // primary key name + aRow.push_back(makeAny(OUString{})); // TODO + // deferrability + aRow.push_back(makeAny(Deferrability::NONE)); + aRows.push_back(aRow); + } + lcl_setRows_throw(xResultSet, 1, aRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getPrimaryKeys(const Any& /*catalog*/, + const OUString& schema, + const OUString& table) +{ + OUString query("SELECT TABLE_CATALOG AS TABLE_CAT, TABLE_SCHEMA " + "AS TABLE_SCHEM, TABLE_NAME, " + "COLUMN_NAME, SEQ_IN_INDEX AS KEY_SEQ," + "INDEX_NAME AS PK_NAME FROM INFORMATION_SCHEMA.STATISTICS " + "WHERE TABLE_SCHEMA LIKE '?' AND TABLE_NAME LIKE '?' AND INDEX_NAME='PRIMARY' " + "ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX"); + + // TODO use prepared stmt instead + // TODO escape schema, table name ? + query = query.replaceFirst("?", schema); + query = query.replaceFirst("?", table); + + Reference<XStatement> statement = m_rConnection.createStatement(); + Reference<XResultSet> rs = statement->executeQuery(query); + return rs; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getIndexInfo(const Any& /*catalog*/, + const OUString& /*schema*/, + const OUString& /*table*/, + sal_Bool /*unique*/, + sal_Bool /*approximate*/) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 11, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getBestRowIdentifier(const Any& /*catalog*/, + const OUString& /*schema*/, + const OUString& /*table*/, + sal_Int32 /*scope*/, + sal_Bool /*nullable*/) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 15, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getTablePrivileges( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*tableNamePattern*/) +{ + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + throw SQLException("getTablePrivileges method not implemented", *this, "IM001", 0, Any()); +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getCrossReference( + const Any& /*primaryCatalog*/, const OUString& /*primarySchema_*/, + const OUString& /*primaryTable_*/, const Any& /*foreignCatalog*/, + const OUString& /*foreignSchema*/, const OUString& /*foreignTable*/) +{ + Reference<XResultSet> xResultSet(getOwnConnection().getDriver().getFactory()->createInstance( + "org.openoffice.comp.helper.DatabaseMetaDataResultSet"), + UNO_QUERY); + std::vector<std::vector<Any>> rRows; + // TODO + SAL_WARN("connectivity.mysqlc", "method not implemented"); + lcl_setRows_throw(xResultSet, 13, rRows); + return xResultSet; +} + +Reference<XResultSet> SAL_CALL ODatabaseMetaData::getUDTs(const Any& /* catalog */, + const OUString& /* schemaPattern */, + const OUString& /* typeNamePattern */, + const Sequence<sal_Int32>& /* types */) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("ODatabaseMetaData::getUDTs", *this); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx new file mode 100644 index 000000000..6814a574c --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_databasemetadata.hxx @@ -0,0 +1,239 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_DATABASEMETADATA_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_DATABASEMETADATA_HXX + +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <cppuhelper/implbase1.hxx> + +namespace connectivity +{ +namespace mysqlc +{ +using ::com::sun::star::uno::Any; + +//************ Class: ODatabaseMetaData + +typedef ::cppu::WeakImplHelper1<css::sdbc::XDatabaseMetaData> ODatabaseMetaData_BASE; + +class ODatabaseMetaData final : public ODatabaseMetaData_BASE +{ + OConnection& m_rConnection; + MYSQL* m_pMySql; + +public: + const OConnection& getOwnConnection() const { return m_rConnection; } + + explicit ODatabaseMetaData(OConnection& _rCon, MYSQL* pMySql); + virtual ~ODatabaseMetaData() override; + + // as I mentioned before this interface is really BIG + // XDatabaseMetaData + sal_Bool SAL_CALL allProceduresAreCallable() override; + sal_Bool SAL_CALL allTablesAreSelectable() override; + OUString SAL_CALL getURL() override; + OUString SAL_CALL getUserName() override; + sal_Bool SAL_CALL isReadOnly() override; + sal_Bool SAL_CALL nullsAreSortedHigh() override; + sal_Bool SAL_CALL nullsAreSortedLow() override; + sal_Bool SAL_CALL nullsAreSortedAtStart() override; + sal_Bool SAL_CALL nullsAreSortedAtEnd() override; + OUString SAL_CALL getDatabaseProductName() override; + OUString SAL_CALL getDatabaseProductVersion() override; + OUString SAL_CALL getDriverName() override; + OUString SAL_CALL getDriverVersion() override; + sal_Int32 SAL_CALL getDriverMajorVersion() override; + sal_Int32 SAL_CALL getDriverMinorVersion() override; + sal_Bool SAL_CALL usesLocalFiles() override; + sal_Bool SAL_CALL usesLocalFilePerTable() override; + sal_Bool SAL_CALL supportsMixedCaseIdentifiers() override; + sal_Bool SAL_CALL storesUpperCaseIdentifiers() override; + sal_Bool SAL_CALL storesLowerCaseIdentifiers() override; + sal_Bool SAL_CALL storesMixedCaseIdentifiers() override; + sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers() override; + sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers() override; + sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers() override; + sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers() override; + OUString SAL_CALL getIdentifierQuoteString() override; + OUString SAL_CALL getSQLKeywords() override; + OUString SAL_CALL getNumericFunctions() override; + OUString SAL_CALL getStringFunctions() override; + OUString SAL_CALL getSystemFunctions() override; + OUString SAL_CALL getTimeDateFunctions() override; + OUString SAL_CALL getSearchStringEscape() override; + OUString SAL_CALL getExtraNameCharacters() override; + sal_Bool SAL_CALL supportsAlterTableWithAddColumn() override; + sal_Bool SAL_CALL supportsAlterTableWithDropColumn() override; + sal_Bool SAL_CALL supportsColumnAliasing() override; + sal_Bool SAL_CALL nullPlusNonNullIsNull() override; + sal_Bool SAL_CALL supportsTypeConversion() override; + sal_Bool SAL_CALL supportsConvert(sal_Int32 fromType, sal_Int32 toType) override; + sal_Bool SAL_CALL supportsTableCorrelationNames() override; + sal_Bool SAL_CALL supportsDifferentTableCorrelationNames() override; + sal_Bool SAL_CALL supportsExpressionsInOrderBy() override; + sal_Bool SAL_CALL supportsOrderByUnrelated() override; + sal_Bool SAL_CALL supportsGroupBy() override; + sal_Bool SAL_CALL supportsGroupByUnrelated() override; + sal_Bool SAL_CALL supportsGroupByBeyondSelect() override; + sal_Bool SAL_CALL supportsLikeEscapeClause() override; + sal_Bool SAL_CALL supportsMultipleResultSets() override; + sal_Bool SAL_CALL supportsMultipleTransactions() override; + sal_Bool SAL_CALL supportsNonNullableColumns() override; + sal_Bool SAL_CALL supportsMinimumSQLGrammar() override; + sal_Bool SAL_CALL supportsCoreSQLGrammar() override; + sal_Bool SAL_CALL supportsExtendedSQLGrammar() override; + sal_Bool SAL_CALL supportsANSI92EntryLevelSQL() override; + sal_Bool SAL_CALL supportsANSI92IntermediateSQL() override; + sal_Bool SAL_CALL supportsANSI92FullSQL() override; + sal_Bool SAL_CALL supportsIntegrityEnhancementFacility() override; + sal_Bool SAL_CALL supportsOuterJoins() override; + sal_Bool SAL_CALL supportsFullOuterJoins() override; + sal_Bool SAL_CALL supportsLimitedOuterJoins() override; + OUString SAL_CALL getSchemaTerm() override; + OUString SAL_CALL getProcedureTerm() override; + OUString SAL_CALL getCatalogTerm() override; + sal_Bool SAL_CALL isCatalogAtStart() override; + OUString SAL_CALL getCatalogSeparator() override; + sal_Bool SAL_CALL supportsSchemasInDataManipulation() override; + sal_Bool SAL_CALL supportsSchemasInProcedureCalls() override; + sal_Bool SAL_CALL supportsSchemasInTableDefinitions() override; + sal_Bool SAL_CALL supportsSchemasInIndexDefinitions() override; + sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions() override; + sal_Bool SAL_CALL supportsCatalogsInDataManipulation() override; + sal_Bool SAL_CALL supportsCatalogsInProcedureCalls() override; + sal_Bool SAL_CALL supportsCatalogsInTableDefinitions() override; + sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions() override; + sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions() override; + sal_Bool SAL_CALL supportsPositionedDelete() override; + sal_Bool SAL_CALL supportsPositionedUpdate() override; + sal_Bool SAL_CALL supportsSelectForUpdate() override; + sal_Bool SAL_CALL supportsStoredProcedures() override; + sal_Bool SAL_CALL supportsSubqueriesInComparisons() override; + sal_Bool SAL_CALL supportsSubqueriesInExists() override; + sal_Bool SAL_CALL supportsSubqueriesInIns() override; + sal_Bool SAL_CALL supportsSubqueriesInQuantifieds() override; + sal_Bool SAL_CALL supportsCorrelatedSubqueries() override; + sal_Bool SAL_CALL supportsUnion() override; + sal_Bool SAL_CALL supportsUnionAll() override; + sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit() override; + sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback() override; + sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit() override; + sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback() override; + sal_Int32 SAL_CALL getMaxBinaryLiteralLength() override; + sal_Int32 SAL_CALL getMaxCharLiteralLength() override; + sal_Int32 SAL_CALL getMaxColumnNameLength() override; + sal_Int32 SAL_CALL getMaxColumnsInGroupBy() override; + sal_Int32 SAL_CALL getMaxColumnsInIndex() override; + sal_Int32 SAL_CALL getMaxColumnsInOrderBy() override; + sal_Int32 SAL_CALL getMaxColumnsInSelect() override; + sal_Int32 SAL_CALL getMaxColumnsInTable() override; + sal_Int32 SAL_CALL getMaxConnections() override; + sal_Int32 SAL_CALL getMaxCursorNameLength() override; + sal_Int32 SAL_CALL getMaxIndexLength() override; + sal_Int32 SAL_CALL getMaxSchemaNameLength() override; + sal_Int32 SAL_CALL getMaxProcedureNameLength() override; + sal_Int32 SAL_CALL getMaxCatalogNameLength() override; + sal_Int32 SAL_CALL getMaxRowSize() override; + sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs() override; + sal_Int32 SAL_CALL getMaxStatementLength() override; + sal_Int32 SAL_CALL getMaxStatements() override; + sal_Int32 SAL_CALL getMaxTableNameLength() override; + sal_Int32 SAL_CALL getMaxTablesInSelect() override; + sal_Int32 SAL_CALL getMaxUserNameLength() override; + sal_Int32 SAL_CALL getDefaultTransactionIsolation() override; + sal_Bool SAL_CALL supportsTransactions() override; + sal_Bool SAL_CALL supportsTransactionIsolationLevel(sal_Int32 level) override; + sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions() override; + sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly() override; + sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit() override; + sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions() override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getProcedures(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getProcedureColumns(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern, + const OUString& columnNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getTables(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence<OUString>& types) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getSchemas() override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getCatalogs() override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getTableTypes() override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getColumns(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getColumnPrivileges(const Any& catalog, const OUString& schema, + const OUString& table, + const OUString& columnNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getTablePrivileges(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getBestRowIdentifier(const Any& catalog, const OUString& schema, + const OUString& table, sal_Int32 scope, + sal_Bool nullable) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL + getVersionColumns(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL + getPrimaryKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL + getImportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL + getExportedKeys(const Any& catalog, const OUString& schema, const OUString& table) override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getCrossReference(const Any& primaryCatalog, const OUString& primarySchema, + const OUString& primaryTable, const Any& foreignCatalog, + const OUString& foreignSchema, + const OUString& foreignTable) override; + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getTypeInfo() override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getIndexInfo(const Any& catalog, const OUString& schema, const OUString& table, + sal_Bool unique, sal_Bool approximate) override; + sal_Bool SAL_CALL supportsResultSetType(sal_Int32 setType) override; + sal_Bool SAL_CALL supportsResultSetConcurrency(sal_Int32 setType, + sal_Int32 concurrency) override; + sal_Bool SAL_CALL ownUpdatesAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL ownDeletesAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL ownInsertsAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL othersUpdatesAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL othersDeletesAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL othersInsertsAreVisible(sal_Int32 setType) override; + sal_Bool SAL_CALL updatesAreDetected(sal_Int32 setType) override; + sal_Bool SAL_CALL deletesAreDetected(sal_Int32 setType) override; + sal_Bool SAL_CALL insertsAreDetected(sal_Int32 setType) override; + sal_Bool SAL_CALL supportsBatchUpdates() override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getUDTs(const Any& catalog, const OUString& schemaPattern, + const OUString& typeNamePattern, + const css::uno::Sequence<sal_Int32>& types) override; + css::uno::Reference<css::sdbc::XConnection> SAL_CALL getConnection() override; +}; +} +} + +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_DATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx b/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx new file mode 100644 index 000000000..c7c88d03e --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.cxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 "mysqlc_driver.hxx" +#include "mysqlc_connection.hxx" + +using namespace css::uno; +using namespace css::lang; +using namespace css::beans; +using namespace css::sdbc; +using namespace connectivity::mysqlc; + +#include <cppuhelper/supportsservice.hxx> + +MysqlCDriver::MysqlCDriver(const Reference<XMultiServiceFactory>& _rxFactory) + : ODriver_BASE(m_aMutex) + , m_xFactory(_rxFactory) +{ +} + +void MysqlCDriver::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + // when driver will be destroyed so all our connections have to be destroyed as well + for (auto const& connection : m_xConnections) + { + Reference<XComponent> xComp(connection.get(), UNO_QUERY); + if (xComp.is()) + { + xComp->dispose(); + } + } + m_xConnections.clear(); + + ODriver_BASE::disposing(); +} + +// static ServiceInfo +OUString MysqlCDriver::getImplementationName_Static() +{ + return "com.sun.star.comp.sdbc.mysqlc.MysqlCDriver"; +} + +Sequence<OUString> MysqlCDriver::getSupportedServiceNames_Static() +{ + return { "com.sun.star.sdbc.Driver" }; +} + +OUString SAL_CALL MysqlCDriver::getImplementationName() { return getImplementationName_Static(); } + +sal_Bool SAL_CALL MysqlCDriver::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence<OUString> SAL_CALL MysqlCDriver::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference<XConnection> SAL_CALL MysqlCDriver::connect(const OUString& url, + const Sequence<PropertyValue>& info) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + if (!acceptsURL(url)) + { + return nullptr; + } + + Reference<XConnection> xConn; + // create a new connection with the given properties and append it to our vector + OConnection* pCon = new OConnection(*this); + xConn = pCon; + + pCon->construct(url, info); + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + return xConn; +} + +sal_Bool SAL_CALL MysqlCDriver::acceptsURL(const OUString& url) +{ + return url.startsWith("sdbc:mysqlc:") || url.startsWith("sdbc:mysql:mysqlc:"); +} + +Sequence<DriverPropertyInfo> SAL_CALL +MysqlCDriver::getPropertyInfo(const OUString& url, const Sequence<PropertyValue>& /* info */) +{ + if (acceptsURL(url)) + { + ::std::vector<DriverPropertyInfo> aDriverInfo; + + aDriverInfo.push_back(DriverPropertyInfo("Hostname", "Name of host", true, "localhost", + Sequence<OUString>())); + aDriverInfo.push_back( + DriverPropertyInfo("Port", "Port", true, "3306", Sequence<OUString>())); + return Sequence<DriverPropertyInfo>(aDriverInfo.data(), aDriverInfo.size()); + } + + return Sequence<DriverPropertyInfo>(); +} + +sal_Int32 SAL_CALL MysqlCDriver::getMajorVersion() { return MARIADBC_VERSION_MAJOR; } + +sal_Int32 SAL_CALL MysqlCDriver::getMinorVersion() { return MARIADBC_VERSION_MINOR; } + +namespace connectivity::mysqlc +{ +Reference<XInterface> MysqlCDriver_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) +{ + return (*(new MysqlCDriver(_rxFactory))); +} + +void checkDisposed(bool _bThrow) +{ + if (_bThrow) + { + throw DisposedException(); + } +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx b/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx new file mode 100644 index 000000000..b55d9cfee --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_driver.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 . + */ +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_DRIVER_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_DRIVER_HXX + +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <cppuhelper/compbase2.hxx> +#include <osl/module.h> + +namespace connectivity +{ +namespace mysqlc +{ +using css::sdbc::SQLException; +using css::uno::Exception; +using css::uno::Reference; +using css::uno::RuntimeException; +using css::uno::Sequence; + +Reference<css::uno::XInterface> +MysqlCDriver_CreateInstance(const Reference<css::lang::XMultiServiceFactory>& _rxFactory); + +typedef ::cppu::WeakComponentImplHelper2<css::sdbc::XDriver, css::lang::XServiceInfo> ODriver_BASE; + +typedef void* (*OMysqlCConnection_CreateInstanceFunction)(void* _pDriver); + +class MysqlCDriver : public ODriver_BASE +{ +protected: + Reference<css::lang::XMultiServiceFactory> m_xFactory; + ::osl::Mutex m_aMutex; // mutex is need to control member access + OWeakRefArray m_xConnections; // vector containing a list + // of all the Connection objects + // for this Driver +#ifdef BUNDLE_MARIADB + oslModule m_hCConnModule; + bool m_bAttemptedLoadCConn; +#endif +public: + explicit MysqlCDriver(const Reference<css::lang::XMultiServiceFactory>& _rxFactory); + + // OComponentHelper + void SAL_CALL disposing() override; + // XInterface + static OUString getImplementationName_Static(); + static Sequence<OUString> getSupportedServiceNames_Static(); + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + // XDriver + Reference<css::sdbc::XConnection> SAL_CALL + connect(const OUString& url, const Sequence<css::beans::PropertyValue>& info) override; + + sal_Bool SAL_CALL acceptsURL(const OUString& url) override; + Sequence<css::sdbc::DriverPropertyInfo> SAL_CALL + getPropertyInfo(const OUString& url, const Sequence<css::beans::PropertyValue>& info) override; + + sal_Int32 SAL_CALL getMajorVersion() override; + sal_Int32 SAL_CALL getMinorVersion() override; + + const Reference<css::lang::XMultiServiceFactory>& getFactory() const { return m_xFactory; } + + static rtl_TextEncoding getDefaultEncoding() { return RTL_TEXTENCODING_UTF8; } +}; +} /* mysqlc */ +} /* connectivity */ + +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_DRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.cxx b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx new file mode 100644 index 000000000..7ed11fe3f --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx @@ -0,0 +1,340 @@ +/* -*- 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 "mysqlc_general.hxx" + +#include <sal/log.hxx> +#include <rtl/ustring.hxx> + +#include <com/sun/star/sdbc/DataType.hpp> + +using com::sun::star::sdbc::SQLException; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; + +using namespace rtl; + +namespace mysqlc_sdbc_driver +{ +void allocateSqlVar(void** mem, enum_field_types eType, unsigned nSize) +{ + assert(mem); + switch (eType) + { + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + *mem = malloc(sizeof(sal_Int32)); + break; + case MYSQL_TYPE_SHORT: + *mem = malloc(sizeof(sal_Int16)); + break; + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_TINY: + *mem = malloc(sizeof(sal_Int8)); + break; + case MYSQL_TYPE_LONGLONG: + *mem = malloc(sizeof(sal_Int64)); + break; + case MYSQL_TYPE_FLOAT: + *mem = malloc(sizeof(float)); + break; + case MYSQL_TYPE_DOUBLE: + *mem = malloc(sizeof(double)); + break; + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_YEAR: // FIXME below + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_GEOMETRY: + *mem = malloc(sizeof(MYSQL_TIME)); + break; + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + *mem = malloc(sizeof(char) * nSize); + break; + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + *mem = nullptr; + break; + default: + SAL_WARN("connectivity.mysqlc", "unknown enum_field_type"); + } +} + +void throwFeatureNotImplementedException(const char* _pAsciiFeatureName, + const css::uno::Reference<XInterface>& _rxContext) +{ + const OUString sMessage + = OUString::createFromAscii(_pAsciiFeatureName) + ": feature not implemented."; + throw SQLException(sMessage, _rxContext, "HYC00", 0, Any()); +} + +void throwInvalidArgumentException(const char* _pAsciiFeatureName, + const css::uno::Reference<XInterface>& _rxContext) +{ + const OUString sMessage + = OUString::createFromAscii(_pAsciiFeatureName) + ": invalid arguments."; + throw SQLException(sMessage, _rxContext, "HYC00", 0, Any()); +} + +void throwSQLExceptionWithMsg(const char* msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference<css::uno::XInterface>& _context, + const rtl_TextEncoding encoding) +{ + OString errorMsg{ msg }; + throwSQLExceptionWithMsg(OStringToOUString(errorMsg, encoding), SQLSTATE, errorNum, _context); +} + +void throwSQLExceptionWithMsg(const OUString& msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference<css::uno::XInterface>& _context) +{ + throw SQLException(msg, _context, OStringToOUString(SQLSTATE, RTL_TEXTENCODING_ASCII_US), + errorNum, Any()); +} + +sal_Int32 mysqlToOOOType(int eType, int charsetnr) noexcept +{ + // charset number 63 indicates binary + switch (eType) + { + case MYSQL_TYPE_BIT: + return css::sdbc::DataType::VARCHAR; + + case MYSQL_TYPE_TINY: + return css::sdbc::DataType::TINYINT; + + case MYSQL_TYPE_SHORT: + return css::sdbc::DataType::SMALLINT; + + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + return css::sdbc::DataType::INTEGER; + + case MYSQL_TYPE_LONGLONG: + return css::sdbc::DataType::BIGINT; + + case MYSQL_TYPE_FLOAT: + return css::sdbc::DataType::REAL; + + case MYSQL_TYPE_DOUBLE: + return css::sdbc::DataType::DOUBLE; + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return css::sdbc::DataType::DECIMAL; + + case MYSQL_TYPE_STRING: + if (charsetnr == 63) + return css::sdbc::DataType::BINARY; + return css::sdbc::DataType::CHAR; + + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_VAR_STRING: + if (charsetnr == 63) + return css::sdbc::DataType::VARBINARY; + return css::sdbc::DataType::VARCHAR; + + case MYSQL_TYPE_BLOB: + if (charsetnr == 63) + return css::sdbc::DataType::LONGVARBINARY; + return css::sdbc::DataType::LONGVARCHAR; + + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + return css::sdbc::DataType::TIMESTAMP; + + case MYSQL_TYPE_DATE: + return css::sdbc::DataType::DATE; + + case MYSQL_TYPE_TIME: + return css::sdbc::DataType::TIME; + + case MYSQL_TYPE_GEOMETRY: + return css::sdbc::DataType::VARCHAR; + + case MYSQL_TYPE_NULL: + return css::sdbc::DataType::SQLNULL; + } + + OSL_FAIL("mysqlToOOOType: unhandled case, falling back to VARCHAR"); + return css::sdbc::DataType::VARCHAR; +} + +sal_Int32 mysqlStrToOOOType(const OUString& sType) +{ + // TODO other types. + if (sType.equalsIgnoreAsciiCase("tiny") || sType.equalsIgnoreAsciiCase("tinyint")) + return css::sdbc::DataType::TINYINT; + if (sType.equalsIgnoreAsciiCase("smallint") || sType.equalsIgnoreAsciiCase("mediumint")) + return css::sdbc::DataType::SMALLINT; + if (sType.equalsIgnoreAsciiCase("longtext")) + return css::sdbc::DataType::LONGVARCHAR; + if (sType.equalsIgnoreAsciiCase("int")) + return css::sdbc::DataType::INTEGER; + if (sType.equalsIgnoreAsciiCase("varchar") || sType.equalsIgnoreAsciiCase("set") + || sType.equalsIgnoreAsciiCase("enum")) + return css::sdbc::DataType::VARCHAR; + if (sType.equalsIgnoreAsciiCase("bigint")) + return css::sdbc::DataType::BIGINT; + if (sType.equalsIgnoreAsciiCase("blob") || sType.equalsIgnoreAsciiCase("longblob")) + return css::sdbc::DataType::BLOB; + if (sType.equalsIgnoreAsciiCase("varbinary")) + return css::sdbc::DataType::VARBINARY; + if (sType.equalsIgnoreAsciiCase("char")) + return css::sdbc::DataType::CHAR; + if (sType.equalsIgnoreAsciiCase("text")) + return css::sdbc::DataType::CLOB; + if (sType.equalsIgnoreAsciiCase("binary")) + return css::sdbc::DataType::BINARY; + if (sType.equalsIgnoreAsciiCase("time")) + return css::sdbc::DataType::TIME; + if (sType.equalsIgnoreAsciiCase("date")) + return css::sdbc::DataType::DATE; + if (sType.equalsIgnoreAsciiCase("datetime") || sType.equalsIgnoreAsciiCase("timestamp")) + return css::sdbc::DataType::TIMESTAMP; + if (sType.equalsIgnoreAsciiCase("decimal")) + return css::sdbc::DataType::DECIMAL; + if (sType.equalsIgnoreAsciiCase("real") || sType.equalsIgnoreAsciiCase("float")) + return css::sdbc::DataType::REAL; + if (sType.equalsIgnoreAsciiCase("double")) + return css::sdbc::DataType::DOUBLE; + if (sType.equalsIgnoreAsciiCase("bit") || sType.equalsIgnoreAsciiCase("bool") + || sType.equalsIgnoreAsciiCase("boolean")) + return css::sdbc::DataType::BOOLEAN; + OSL_FAIL("Unknown type name from string, failing back to varchar."); + return css::sdbc::DataType::VARCHAR; +} + +OUString mysqlTypeToStr(unsigned type, unsigned flags) +{ + bool isUnsigned = (flags & UNSIGNED_FLAG) != 0; + bool isZerofill = (flags & ZEROFILL_FLAG) != 0; + switch (type) + { + case MYSQL_TYPE_BIT: + return OUString{ "BIT" }; + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return isUnsigned ? (isZerofill ? OUString{ "DECIMAL UNSIGNED ZEROFILL" } + : OUString{ "DECIMAL UNSIGNED" }) + : OUString{ "DECIMAL" }; + case MYSQL_TYPE_TINY: + return isUnsigned ? (isZerofill ? OUString{ "TINYINT UNSIGNED ZEROFILL" } + : OUString{ "TINYINT UNSIGNED" }) + : OUString{ "TINYINT" }; + case MYSQL_TYPE_SHORT: + return isUnsigned ? (isZerofill ? OUString{ "SMALLINT UNSIGNED ZEROFILL" } + : OUString{ "SMALLINT UNSIGNED" }) + : OUString{ "SMALLINT" }; + case MYSQL_TYPE_LONG: + return isUnsigned ? (isZerofill ? OUString{ "INT UNSIGNED ZEROFILL" } + : OUString{ "INT UNSIGNED" }) + : OUString{ "INT" }; + case MYSQL_TYPE_FLOAT: + return isUnsigned ? (isZerofill ? OUString{ "FLOAT UNSIGNED ZEROFILL" } + : OUString{ "FLOAT UNSIGNED" }) + : OUString{ "FLOAT" }; + case MYSQL_TYPE_DOUBLE: + return isUnsigned ? (isZerofill ? OUString{ "DOUBLE UNSIGNED ZEROFILL" } + : OUString{ "DOUBLE UNSIGNED" }) + : OUString{ "DOUBLE" }; + case MYSQL_TYPE_NULL: + return OUString{ "NULL" }; + case MYSQL_TYPE_TIMESTAMP: + return OUString{ "TIMESTAMP" }; + case MYSQL_TYPE_LONGLONG: + return isUnsigned ? (isZerofill ? OUString{ "BIGINT UNSIGNED ZEROFILL" } + : OUString{ "BIGINT UNSIGNED" }) + : OUString{ "BIGINT" }; + case MYSQL_TYPE_INT24: + return isUnsigned ? (isZerofill ? OUString{ "MEDIUMINT UNSIGNED ZEROFILL" } + : OUString{ "MEDIUMINT UNSIGNED" }) + : OUString{ "MEDIUMINT" }; + case MYSQL_TYPE_DATE: + return OUString{ "DATE" }; + case MYSQL_TYPE_TIME: + return OUString{ "TIME" }; + case MYSQL_TYPE_DATETIME: + return OUString{ "DATETIME" }; + case MYSQL_TYPE_TINY_BLOB: + { + return OUString{ "TINYBLOB" }; + } + case MYSQL_TYPE_MEDIUM_BLOB: + { + return OUString{ "MEDIUMBLOB" }; + } + case MYSQL_TYPE_LONG_BLOB: + { + return OUString{ "LONGBLOB" }; + } + case MYSQL_TYPE_BLOB: + { + return OUString{ "BLOB" }; + } + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VAR_STRING: + if (flags & ENUM_FLAG) + { + return OUString{ "ENUM" }; + } + if (flags & SET_FLAG) + { + return OUString{ "SET" }; + } + return OUString{ "VARCHAR" }; + case MYSQL_TYPE_STRING: + if (flags & ENUM_FLAG) + { + return OUString{ "ENUM" }; + } + if (flags & SET_FLAG) + { + return OUString{ "SET" }; + } + return OUString{ "CHAR" }; + case MYSQL_TYPE_YEAR: + return OUString{ "YEAR" }; + case MYSQL_TYPE_GEOMETRY: + return OUString{ "GEOMETRY" }; + default: + return OUString{ "UNKNOWN" }; + } +} + +OUString convert(const ::std::string& _string, const rtl_TextEncoding encoding) +{ + return OUString(_string.c_str(), _string.size(), encoding); +} + +} /* namespace */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.hxx b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx new file mode 100644 index 000000000..c00a11f41 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx @@ -0,0 +1,119 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_GENERAL_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_GENERAL_HXX + +#include <config_lgpl.h> + +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <osl/diagnose.h> +#include <mysql.h> + +#if defined __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated" +#endif + +#if defined __GNUC__ +#pragma GCC diagnostic pop +#endif + +namespace mysqlc_sdbc_driver +{ +template <typename T> +void resetSqlVar(void** target, T* pValue, enum_field_types type, sal_Int32 nSize = 0) +{ + if (*target) + { + free(*target); + *target = nullptr; + } + constexpr auto nUnitSize = sizeof(T); + switch (type) + { + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + *target = malloc(nUnitSize); + memcpy(*target, pValue, nUnitSize); + break; + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + *target = malloc(nUnitSize * nSize); + memcpy(*target, pValue, nUnitSize * nSize); + break; + case MYSQL_TYPE_NULL: + // nothing I guess + break; + default: + OSL_FAIL("resetSqlVar: unknown enum_field_type"); + } +} + +void allocateSqlVar(void** mem, enum_field_types eType, unsigned nSize = 0); + +void throwFeatureNotImplementedException( + const char* _pAsciiFeatureName, const css::uno::Reference<css::uno::XInterface>& _rxContext); + +void throwInvalidArgumentException(const char* _pAsciiFeatureName, + const css::uno::Reference<css::uno::XInterface>& _rxContext); + +void throwSQLExceptionWithMsg(const char* msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference<css::uno::XInterface>& _context, + const rtl_TextEncoding encoding); + +void throwSQLExceptionWithMsg(const OUString& msg, const char* SQLSTATE, unsigned int errorNum, + const css::uno::Reference<css::uno::XInterface>& _context); + +sal_Int32 mysqlToOOOType(int eType, int charsetnr) noexcept; + +OUString mysqlTypeToStr(unsigned mysql_type, unsigned mysql_flags); + +sal_Int32 mysqlStrToOOOType(const OUString& sType); + +OUString convert(const ::std::string& _string, const rtl_TextEncoding encoding); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx new file mode 100644 index 000000000..8031bfdf2 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx @@ -0,0 +1,1084 @@ +/* -*- 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 "mysqlc_propertyids.hxx" +#include "mysqlc_general.hxx" +#include "mysqlc_prepared_resultset.hxx" +#include "mysqlc_resultsetmetadata.hxx" + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <sal/log.hxx> + +using namespace rtl; + +#include <cstdlib> + +using namespace connectivity::mysqlc; +using namespace connectivity; +using namespace cppu; +using namespace com::sun::star; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; +using namespace ::comphelper; +using ::osl::MutexGuard; + +#include <typeindex> + +namespace +{ +std::type_index getTypeFromMysqlType(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_TINY: + return std::type_index(typeid(sal_Int8)); + case MYSQL_TYPE_SHORT: + return std::type_index(typeid(sal_Int16)); + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + return std::type_index(typeid(sal_Int32)); + case MYSQL_TYPE_LONGLONG: + return std::type_index(typeid(sal_Int64)); + case MYSQL_TYPE_FLOAT: + return std::type_index(typeid(float)); + case MYSQL_TYPE_DOUBLE: + return std::type_index(typeid(double)); + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + return std::type_index(typeid(DateTime)); + case MYSQL_TYPE_DATE: + return std::type_index(typeid(Date)); + case MYSQL_TYPE_TIME: + return std::type_index(typeid(Time)); + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return std::type_index(typeid(OUString)); + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_NULL: + default: + return std::type_index(typeid(nullptr)); + } +} +} + +bool OPreparedResultSet::fetchResult() +{ + // allocate array if it does not exist + if (m_aData == nullptr) + { + m_aData.reset(new MYSQL_BIND[m_nColumnCount]); + memset(m_aData.get(), 0, m_nColumnCount * sizeof(MYSQL_BIND)); + m_aMetaData.reset(new BindMetaData[m_nColumnCount]); + } + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) + { + m_aMetaData[i].is_null = false; + m_aMetaData[i].length = 0l; + m_aMetaData[i].error = false; + + m_aData[i].is_null = &m_aMetaData[i].is_null; + m_aData[i].buffer_length = m_aFields[i].type == MYSQL_TYPE_BLOB ? 0 : m_aFields[i].length; + m_aData[i].length = &m_aMetaData[i].length; + m_aData[i].error = &m_aMetaData[i].error; + m_aData[i].buffer = nullptr; + m_aData[i].buffer_type = m_aFields[i].type; + + // allocates memory, if it is a fixed size type. If not then nullptr + mysqlc_sdbc_driver::allocateSqlVar(&m_aData[i].buffer, m_aData[i].buffer_type, + m_aFields[i].length); + } + mysql_stmt_bind_result(m_pStmt, m_aData.get()); + int failure = mysql_stmt_fetch(m_pStmt); + + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) + { + if (*m_aData[i].error) + { + // expected if we have a BLOB, as buffer_length is set to 0. We want to + // fetch it piece by piece + // see https://bugs.mysql.com/file.php?id=12361&bug_id=33086 + if (m_aData[i].buffer == nullptr) + { + m_aData[i].buffer_length = *m_aData[i].length; + m_aData[i].buffer = malloc(*m_aData[i].length); + mysql_stmt_fetch_column(m_pStmt, &m_aData[i], i, 0); + } + } + } + + if (failure == 1) + { + MYSQL* pMysql = m_rConnection.getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMysql), mysql_sqlstate(pMysql), + mysql_errno(pMysql), *this, m_encoding); + } + else if (failure == MYSQL_NO_DATA) + return false; + return true; +} + +OUString SAL_CALL OPreparedResultSet::getImplementationName() +{ + return "com.sun.star.sdbcx.mysqlc.ResultSet"; +} + +uno::Sequence<OUString> SAL_CALL OPreparedResultSet::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL OPreparedResultSet::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} +OPreparedResultSet::OPreparedResultSet(OConnection& rConn, OPreparedStatement* pStmt, + MYSQL_STMT* pMyStmt) + : OPreparedResultSet_BASE(m_aMutex) + , OPropertySetHelper(OPreparedResultSet_BASE::rBHelper) + , m_rConnection(rConn) + , m_aStatement(static_cast<OWeakObject*>(pStmt)) + , m_pStmt(pMyStmt) + , m_encoding(rConn.getConnectionEncoding()) + , m_nColumnCount(mysql_stmt_field_count(pMyStmt)) +{ + m_pResult = mysql_stmt_result_metadata(m_pStmt); + if (m_pResult != nullptr) + mysql_stmt_store_result(m_pStmt); + m_aFields = mysql_fetch_fields(m_pResult); + m_nRowCount = mysql_stmt_num_rows(pMyStmt); +} + +void OPreparedResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + MutexGuard aGuard(m_aMutex); + + m_aStatement = nullptr; + m_xMetaData = nullptr; +} + +Any SAL_CALL OPreparedResultSet::queryInterface(const Type& rType) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OPreparedResultSet_BASE::queryInterface(rType); + } + return aRet; +} + +uno::Sequence<Type> SAL_CALL OPreparedResultSet::getTypes() +{ + OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return concatSequences(aTypes.getTypes(), OPreparedResultSet_BASE::getTypes()); +} + +sal_Int32 SAL_CALL OPreparedResultSet::findColumn(const OUString& columnName) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult); + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) + { + if (columnName.equalsIgnoreAsciiCaseAscii(pFields[i].name)) + return i + 1; // sdbc indexes from 1 + } + + throw SQLException("The column name '" + columnName + "' is not valid.", *this, "42S22", 0, + Any()); +} + +template <typename T> T OPreparedResultSet::safelyRetrieveValue(sal_Int32 nColumnIndex) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(nColumnIndex); + if (*m_aData[nColumnIndex - 1].is_null) + { + m_bWasNull = true; + return T(); + } + m_bWasNull = false; + + return retrieveValue<T>(nColumnIndex); +} + +template <typename T> T OPreparedResultSet::retrieveValue(sal_Int32 nColumnIndex) +{ + if (getTypeFromMysqlType(m_aFields[nColumnIndex - 1].type) == std::type_index(typeid(T))) + return *static_cast<T*>(m_aData[nColumnIndex - 1].buffer); + else + return getRowSetValue(nColumnIndex); +} + +template <> uno::Sequence<sal_Int8> OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + // TODO make conversion possible + return uno::Sequence<sal_Int8>(static_cast<sal_Int8 const*>(m_aData[column - 1].buffer), + *m_aData[column - 1].length); +} + +template <> Date OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(Date))) + return getRowSetValue(column); + const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer); + + Date d; + d.Year = pTime->year; + d.Month = pTime->month; + d.Day = pTime->day; + return d; +} + +template <> Time OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(Time))) + return getRowSetValue(column); + const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer); + + Time t; + t.Hours = pTime->hour; + t.Minutes = pTime->minute; + t.Seconds = pTime->second; + return t; +} + +template <> DateTime OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(DateTime))) + return getRowSetValue(column); + const MYSQL_TIME* pTime = static_cast<MYSQL_TIME*>(m_aData[column - 1].buffer); + + DateTime t; + t.Year = pTime->year; + t.Month = pTime->month; + t.Day = pTime->day; + t.Hours = pTime->hour; + t.Minutes = pTime->minute; + t.Seconds = pTime->second; + return t; +} + +template <> OUString OPreparedResultSet::retrieveValue(sal_Int32 column) +{ + // redirect call to the appropriate method if needed + // BLOB can be simply read out as string + if (getTypeFromMysqlType(m_aFields[column - 1].type) != std::type_index(typeid(OUString)) + && m_aFields[column - 1].type != MYSQL_TYPE_BLOB) + return getRowSetValue(column); + const char* sStr = static_cast<const char*>(m_aData[column - 1].buffer); + + return OUString(sStr, *m_aData[column - 1].length, m_encoding); +} + +ORowSetValue OPreparedResultSet::getRowSetValue(sal_Int32 nColumnIndex) +{ + switch (m_aFields[nColumnIndex - 1].type) + { + case MYSQL_TYPE_TINY: + return getByte(nColumnIndex); + case MYSQL_TYPE_SHORT: + return getShort(nColumnIndex); + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + return getInt(nColumnIndex); + case MYSQL_TYPE_LONGLONG: + return getLong(nColumnIndex); + case MYSQL_TYPE_FLOAT: + return getFloat(nColumnIndex); + case MYSQL_TYPE_DOUBLE: + return getDouble(nColumnIndex); + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + return getTimestamp(nColumnIndex); + case MYSQL_TYPE_DATE: + return getDate(nColumnIndex); + case MYSQL_TYPE_TIME: + return getTime(nColumnIndex); + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return getString(nColumnIndex); + case MYSQL_TYPE_BLOB: + throw SQLException("Column with type BLOB cannot be converted", *this, "22000", 1, + Any()); + default: + SAL_WARN("connectivity.mysqlc", "OPreparedResultSet::getRowSetValue: unknown type: " + << m_aFields[nColumnIndex - 1].type); + throw SQLException("Unknown column type when fetching result", *this, "22000", 1, + Any()); + } +} + +uno::Reference<XInputStream> SAL_CALL OPreparedResultSet::getBinaryStream(sal_Int32 /*column*/) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBinaryStream", + *this); + return nullptr; +} + +uno::Reference<XInputStream> SAL_CALL OPreparedResultSet::getCharacterStream(sal_Int32 /*column*/) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::getCharacterStream", *this); + return nullptr; +} + +sal_Bool SAL_CALL OPreparedResultSet::getBoolean(sal_Int32 column) +{ + return safelyRetrieveValue<bool>(column); +} + +sal_Int8 SAL_CALL OPreparedResultSet::getByte(sal_Int32 column) +{ + return safelyRetrieveValue<sal_Int8>(column); +} + +uno::Sequence<sal_Int8> SAL_CALL OPreparedResultSet::getBytes(sal_Int32 column) +{ + return safelyRetrieveValue<uno::Sequence<sal_Int8>>(column); +} + +Date SAL_CALL OPreparedResultSet::getDate(sal_Int32 column) +{ + return safelyRetrieveValue<Date>(column); +} + +double SAL_CALL OPreparedResultSet::getDouble(sal_Int32 column) +{ + return safelyRetrieveValue<double>(column); +} + +float SAL_CALL OPreparedResultSet::getFloat(sal_Int32 column) +{ + return safelyRetrieveValue<float>(column); +} + +sal_Int32 SAL_CALL OPreparedResultSet::getInt(sal_Int32 column) +{ + return safelyRetrieveValue<sal_Int32>(column); +} + +sal_Int32 SAL_CALL OPreparedResultSet::getRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return static_cast<sal_Int32>(mysql_field_tell(m_pResult)); +} + +sal_Int64 SAL_CALL OPreparedResultSet::getLong(sal_Int32 column) +{ + return safelyRetrieveValue<sal_Int64>(column); +} + +uno::Reference<XResultSetMetaData> SAL_CALL OPreparedResultSet::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + if (!m_xMetaData.is()) + { + m_xMetaData = new OResultSetMetaData(m_rConnection, m_pResult); + } + return m_xMetaData; +} + +uno::Reference<XArray> SAL_CALL OPreparedResultSet::getArray(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getArray", *this); + return nullptr; +} + +uno::Reference<XClob> SAL_CALL OPreparedResultSet::getClob(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getClob", *this); + return nullptr; +} + +uno::Reference<XBlob> SAL_CALL OPreparedResultSet::getBlob(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBlob", *this); + return nullptr; +} + +uno::Reference<XRef> SAL_CALL OPreparedResultSet::getRef(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getRef", *this); + return nullptr; +} + +Any SAL_CALL OPreparedResultSet::getObject(sal_Int32 column, + const uno::Reference<XNameAccess>& /* typeMap */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + + Any aRet; + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getObject", *this); + return aRet; +} + +sal_Int16 SAL_CALL OPreparedResultSet::getShort(sal_Int32 column) +{ + return safelyRetrieveValue<sal_Int16>(column); +} + +OUString SAL_CALL OPreparedResultSet::getString(sal_Int32 column) +{ + return safelyRetrieveValue<OUString>(column); +} + +Time SAL_CALL OPreparedResultSet::getTime(sal_Int32 column) +{ + return safelyRetrieveValue<Time>(column); +} + +DateTime SAL_CALL OPreparedResultSet::getTimestamp(sal_Int32 column) +{ + return safelyRetrieveValue<DateTime>(column); +} + +sal_Bool SAL_CALL OPreparedResultSet::isBeforeFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_nCurrentRow == 0; +} + +sal_Bool SAL_CALL OPreparedResultSet::isAfterLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_nCurrentRow > m_nRowCount; +} + +sal_Bool SAL_CALL OPreparedResultSet::isFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_nCurrentRow == 1 && !isAfterLast(); +} + +sal_Bool SAL_CALL OPreparedResultSet::isLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_nCurrentRow == m_nRowCount; +} + +void SAL_CALL OPreparedResultSet::beforeFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysql_stmt_data_seek(m_pStmt, 0); + + m_nCurrentRow = 0; + m_aData.reset(); +} + +void SAL_CALL OPreparedResultSet::afterLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::afterLast", *this); +} + +void SAL_CALL OPreparedResultSet::close() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + m_aData.reset(); + m_aMetaData.reset(); + + if (m_pResult) + mysql_free_result(m_pResult); + mysql_stmt_free_result(m_pStmt); + dispose(); +} + +sal_Bool SAL_CALL OPreparedResultSet::first() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysql_stmt_data_seek(m_pStmt, 0); + m_nCurrentRow = 0; + next(); + + return true; +} + +sal_Bool SAL_CALL OPreparedResultSet::last() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysql_stmt_data_seek(m_pStmt, m_nRowCount - 1); + next(); + + return true; +} + +sal_Bool SAL_CALL OPreparedResultSet::absolute(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + sal_Int32 nToGo = row < 0 ? m_nRowCount - row : row - 1; + + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; + if (nToGo < 0) + nToGo = 0; + + mysql_stmt_data_seek(m_pStmt, nToGo); + next(); + + return true; +} + +sal_Bool SAL_CALL OPreparedResultSet::relative(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + if (row == 0) + return true; + + sal_Int32 nToGo = m_nCurrentRow + row; + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; + if (nToGo < 0) + nToGo = 0; + + mysql_stmt_data_seek(m_pStmt, nToGo); + next(); + m_nCurrentRow += row; + + return true; +} + +sal_Bool SAL_CALL OPreparedResultSet::previous() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + if (m_nCurrentRow <= 1) + return false; + + mysql_stmt_data_seek(m_pStmt, m_nCurrentRow - 2); + next(); + --m_nCurrentRow; + return true; +} + +uno::Reference<uno::XInterface> SAL_CALL OPreparedResultSet::getStatement() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_aStatement.get(); +} + +sal_Bool SAL_CALL OPreparedResultSet::rowDeleted() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OPreparedResultSet::rowInserted() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OPreparedResultSet::rowUpdated() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OPreparedResultSet::next() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + bool hasData = fetchResult(); + + // current field cannot be asked as a number. We have to keep track it + // manually. + m_nCurrentRow += 1; + + return hasData; +} + +sal_Bool SAL_CALL OPreparedResultSet::wasNull() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + +void SAL_CALL OPreparedResultSet::cancel() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OPreparedResultSet::clearWarnings() {} + +Any SAL_CALL OPreparedResultSet::getWarnings() { return Any(); } + +void SAL_CALL OPreparedResultSet::insertRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + // you only have to implement this if you want to insert new rows + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::insertRow", *this); +} + +void SAL_CALL OPreparedResultSet::updateRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + // only when you allow updates + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateRow", *this); +} + +void SAL_CALL OPreparedResultSet::deleteRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::deleteRow", *this); +} + +void SAL_CALL OPreparedResultSet::cancelRowUpdates() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::cancelRowUpdates", + *this); +} + +void SAL_CALL OPreparedResultSet::moveToInsertRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + // only when you allow insert's + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::moveToInsertRow", + *this); +} + +void SAL_CALL OPreparedResultSet::moveToCurrentRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OPreparedResultSet::updateNull(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateNull", + *this); +} + +void SAL_CALL OPreparedResultSet::updateBoolean(sal_Int32 column, sal_Bool /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateBoolean", + *this); +} + +void SAL_CALL OPreparedResultSet::updateByte(sal_Int32 column, sal_Int8 /* x */) +{ + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateByte", + *this); +} + +void SAL_CALL OPreparedResultSet::updateShort(sal_Int32 column, sal_Int16 /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateShort", + *this); +} + +void SAL_CALL OPreparedResultSet::updateInt(sal_Int32 column, sal_Int32 /* x */) +{ + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateInt", *this); +} + +void SAL_CALL OPreparedResultSet::updateLong(sal_Int32 column, sal_Int64 /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateLong", + *this); +} + +void SAL_CALL OPreparedResultSet::updateFloat(sal_Int32 column, float /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateFloat", + *this); +} + +void SAL_CALL OPreparedResultSet::updateDouble(sal_Int32 column, double /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateDouble", + *this); +} + +void SAL_CALL OPreparedResultSet::updateString(sal_Int32 column, const OUString& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateString", + *this); +} + +void SAL_CALL OPreparedResultSet::updateBytes(sal_Int32 column, + const uno::Sequence<sal_Int8>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateBytes", + *this); +} + +void SAL_CALL OPreparedResultSet::updateDate(sal_Int32 column, const Date& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateDate", + *this); +} + +void SAL_CALL OPreparedResultSet::updateTime(sal_Int32 column, const Time& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateTime", + *this); +} + +void SAL_CALL OPreparedResultSet::updateTimestamp(sal_Int32 column, const DateTime& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateTimestamp", + *this); +} + +void SAL_CALL OPreparedResultSet::updateBinaryStream(sal_Int32 column, + const uno::Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::updateBinaryStream", *this); +} + +void SAL_CALL OPreparedResultSet::updateCharacterStream(sal_Int32 column, + const uno::Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::updateCharacterStream", *this); +} + +void SAL_CALL OPreparedResultSet::refreshRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::refreshRow", + *this); +} + +void SAL_CALL OPreparedResultSet::updateObject(sal_Int32 column, const Any& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::updateObject", + *this); +} + +void SAL_CALL OPreparedResultSet::updateNumericObject(sal_Int32 column, const Any& /* x */, + sal_Int32 /* scale */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::updateNumericObject", *this); +} + +// XRowLocate +Any SAL_CALL OPreparedResultSet::getBookmark() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + // if you don't want to support bookmark you must remove the XRowLocate interface + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::getBookmark", + *this); + + return Any(); +} + +sal_Bool SAL_CALL OPreparedResultSet::moveToBookmark(const Any& /* bookmark */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OPreparedResultSet::moveRelativeToBookmark(const Any& /* bookmark */, + sal_Int32 /* rows */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedResultSet::moveRelativeToBookmark", *this); + return false; +} + +sal_Int32 SAL_CALL OPreparedResultSet::compareBookmarks(const Any& /* n1 */, const Any& /* n2 */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::compareBookmarks", + *this); + + return CompareBookmark::NOT_EQUAL; +} + +sal_Bool SAL_CALL OPreparedResultSet::hasOrderedBookmarks() { return false; } + +sal_Int32 SAL_CALL OPreparedResultSet::hashBookmark(const Any& /* bookmark */) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::hashBookmark", + *this); + return 0; +} + +// XDeleteRows +uno::Sequence<sal_Int32> + SAL_CALL OPreparedResultSet::deleteRows(const uno::Sequence<Any>& /* rows */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::deleteRows", + *this); + return uno::Sequence<sal_Int32>(); +} + +IPropertyArrayHelper* OPreparedResultSet::createArrayHelper() const +{ + uno::Sequence<Property> aProps(5); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = Property("FetchDirection", PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] + = Property("FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = Property("IsBookmarkable", PROPERTY_ID_ISBOOKMARKABLE, + cppu::UnoType<bool>::get(), PropertyAttribute::READONLY); + pProperties[nPos++] = Property("ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + pProperties[nPos++] = Property("ResultSetType", PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + return new OPropertyArrayHelper(aProps); +} + +IPropertyArrayHelper& OPreparedResultSet::getInfoHelper() { return *getArrayHelper(); } + +sal_Bool OPreparedResultSet::convertFastPropertyValue(Any& /* rConvertedValue */, + Any& /* rOldValue */, sal_Int32 nHandle, + const Any& /* rValue */) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + default:; + } + return false; +} + +void OPreparedResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, + const Any& /* rValue */) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr); + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_FETCHSIZE: + break; + default:; + } +} + +void OPreparedResultSet::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + _rValue <<= false; + break; + case PROPERTY_ID_CURSORNAME: + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + _rValue <<= ResultSetConcurrency::READ_ONLY; + break; + case PROPERTY_ID_RESULTSETTYPE: + _rValue <<= ResultSetType::SCROLL_INSENSITIVE; + break; + case PROPERTY_ID_FETCHDIRECTION: + _rValue <<= FetchDirection::FORWARD; + break; + case PROPERTY_ID_FETCHSIZE: + _rValue <<= sal_Int32(50); + break; + ; + default:; + } +} + +void SAL_CALL OPreparedResultSet::acquire() throw() { OPreparedResultSet_BASE::acquire(); } + +void SAL_CALL OPreparedResultSet::release() throw() { OPreparedResultSet_BASE::release(); } + +css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL OPreparedResultSet::getPropertySetInfo() +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +void OPreparedResultSet::checkColumnIndex(sal_Int32 index) +{ + if (!m_aData) + throw SQLException("Cursor out of range", *this, "HY109", 1, Any()); + if (index < 1 || index > static_cast<int>(m_nColumnCount)) + { + /* static object for efficiency or thread safety is a problem ? */ + throw SQLException("index out of range", *this, "42S22", 1, Any()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx new file mode 100644 index 000000000..4ff64d5b4 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx @@ -0,0 +1,257 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_RESULTSET_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_RESULTSET_HXX + +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_subcomponent.hxx" +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <connectivity/FValue.hxx> + +#include <cppuhelper/compbase12.hxx> + +namespace connectivity +{ +namespace mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::RuntimeException; + +typedef ::cppu::WeakComponentImplHelper12< + css::sdbc::XResultSet, css::sdbc::XRow, css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, css::sdbc::XWarningsSupplier, css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, css::sdbcx::XRowLocate, css::sdbcx::XDeleteRows, css::sdbc::XCloseable, + css::sdbc::XColumnLocate, css::lang::XServiceInfo> + OPreparedResultSet_BASE; + +class OPreparedResultSet final : public OBase_Mutex, + public OPreparedResultSet_BASE, + public ::cppu::OPropertySetHelper, + public OPropertyArrayUsageHelper<OPreparedResultSet> +{ + OConnection& m_rConnection; + css::uno::WeakReferenceHelper m_aStatement; + css::uno::Reference<css::sdbc::XResultSetMetaData> m_xMetaData; + + // non-owning pointers + MYSQL_RES* m_pResult; + MYSQL_STMT* m_pStmt; + MYSQL_FIELD* m_aFields; + + rtl_TextEncoding m_encoding; + sal_Int32 m_nCurrentRow = 0; + sal_Int32 m_nColumnCount; + sal_Int32 m_nRowCount; + + // Use c style arrays, because we have to work with pointers + // on these. + std::unique_ptr<MYSQL_BIND[]> m_aData; + std::unique_ptr<BindMetaData[]> m_aMetaData; + + bool m_bWasNull = false; + + // OPropertyArrayUsageHelper + ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, + sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override; + + template <typename T> T safelyRetrieveValue(const sal_Int32 nColumnIndex); + template <typename T> T retrieveValue(const sal_Int32 nColumnIndex); + connectivity::ORowSetValue getRowSetValue(sal_Int32 nColumnIndex); + + bool fetchResult(); + + // you can't delete objects of this type + virtual ~OPreparedResultSet() override = default; + +public: + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + OPreparedResultSet(OConnection& rConn, OPreparedStatement* pStmt, MYSQL_STMT* pMyStmt); + + // ::cppu::OComponentHelper + void SAL_CALL disposing() override; + + // XInterface + Any SAL_CALL queryInterface(const css::uno::Type& rType) override; + + void SAL_CALL acquire() throw() override; + void SAL_CALL release() throw() override; + + //XTypeProvider + css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override; + + // XPropertySet + css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + + // XResultSet + sal_Bool SAL_CALL next() override; + sal_Bool SAL_CALL isBeforeFirst() override; + sal_Bool SAL_CALL isAfterLast() override; + sal_Bool SAL_CALL isFirst() override; + sal_Bool SAL_CALL isLast() override; + + void SAL_CALL beforeFirst() override; + void SAL_CALL afterLast() override; + + sal_Bool SAL_CALL first() override; + sal_Bool SAL_CALL last() override; + + sal_Int32 SAL_CALL getRow() override; + + sal_Bool SAL_CALL absolute(sal_Int32 row) override; + sal_Bool SAL_CALL relative(sal_Int32 rows) override; + sal_Bool SAL_CALL previous() override; + + void SAL_CALL refreshRow() override; + + sal_Bool SAL_CALL rowUpdated() override; + sal_Bool SAL_CALL rowInserted() override; + sal_Bool SAL_CALL rowDeleted() override; + + css::uno::Reference<css::uno::XInterface> SAL_CALL getStatement() override; + // XRow + sal_Bool SAL_CALL wasNull() override; + + OUString SAL_CALL getString(sal_Int32 column) override; + + sal_Bool SAL_CALL getBoolean(sal_Int32 column) override; + sal_Int8 SAL_CALL getByte(sal_Int32 column) override; + sal_Int16 SAL_CALL getShort(sal_Int32 column) override; + sal_Int32 SAL_CALL getInt(sal_Int32 column) override; + sal_Int64 SAL_CALL getLong(sal_Int32 column) override; + + float SAL_CALL getFloat(sal_Int32 column) override; + double SAL_CALL getDouble(sal_Int32 column) override; + + css::uno::Sequence<sal_Int8> SAL_CALL getBytes(sal_Int32 column) override; + css::util::Date SAL_CALL getDate(sal_Int32 column) override; + css::util::Time SAL_CALL getTime(sal_Int32 column) override; + css::util::DateTime SAL_CALL getTimestamp(sal_Int32 column) override; + + css::uno::Reference<css::io::XInputStream> SAL_CALL getBinaryStream(sal_Int32 column) override; + css::uno::Reference<css::io::XInputStream> + SAL_CALL getCharacterStream(sal_Int32 column) override; + + Any SAL_CALL getObject( + sal_Int32 column, const css::uno::Reference<css::container::XNameAccess>& typeMap) override; + + css::uno::Reference<css::sdbc::XRef> SAL_CALL getRef(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XBlob> SAL_CALL getBlob(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XClob> SAL_CALL getClob(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XArray> SAL_CALL getArray(sal_Int32 column) override; + + // XResultSetMetaDataSupplier + css::uno::Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override; + + // XCancellable + void SAL_CALL cancel() override; + + // XCloseable + void SAL_CALL close() override; + + // XWarningsSupplier + Any SAL_CALL getWarnings() override; + + void SAL_CALL clearWarnings() override; + + // XResultSetUpdate + void SAL_CALL insertRow() override; + void SAL_CALL updateRow() override; + void SAL_CALL deleteRow() override; + void SAL_CALL cancelRowUpdates() override; + void SAL_CALL moveToInsertRow() override; + void SAL_CALL moveToCurrentRow() override; + + // XRowUpdate + void SAL_CALL updateNull(sal_Int32 column) override; + void SAL_CALL updateBoolean(sal_Int32 column, sal_Bool x) override; + void SAL_CALL updateByte(sal_Int32 column, sal_Int8 x) override; + void SAL_CALL updateShort(sal_Int32 column, sal_Int16 x) override; + void SAL_CALL updateInt(sal_Int32 column, sal_Int32 x) override; + void SAL_CALL updateLong(sal_Int32 column, sal_Int64 x) override; + void SAL_CALL updateFloat(sal_Int32 column, float x) override; + void SAL_CALL updateDouble(sal_Int32 column, double x) override; + void SAL_CALL updateString(sal_Int32 column, const OUString& x) override; + void SAL_CALL updateBytes(sal_Int32 column, const css::uno::Sequence<sal_Int8>& x) override; + void SAL_CALL updateDate(sal_Int32 column, const css::util::Date& x) override; + void SAL_CALL updateTime(sal_Int32 column, const css::util::Time& x) override; + void SAL_CALL updateTimestamp(sal_Int32 column, const css::util::DateTime& x) override; + void SAL_CALL updateBinaryStream(sal_Int32 column, + const css::uno::Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + void SAL_CALL updateCharacterStream(sal_Int32 column, + const css::uno::Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + void SAL_CALL updateObject(sal_Int32 column, const Any& x) override; + void SAL_CALL updateNumericObject(sal_Int32 column, const Any& x, sal_Int32 scale) override; + + // XColumnLocate + sal_Int32 SAL_CALL findColumn(const OUString& columnName) override; + + // XRowLocate + Any SAL_CALL getBookmark() override; + + sal_Bool SAL_CALL moveToBookmark(const Any& bookmark) override; + sal_Bool SAL_CALL moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) override; + sal_Int32 SAL_CALL compareBookmarks(const Any& first, const Any& second) override; + sal_Bool SAL_CALL hasOrderedBookmarks() override; + sal_Int32 SAL_CALL hashBookmark(const Any& bookmark) override; + + // XDeleteRows + css::uno::Sequence<sal_Int32> SAL_CALL deleteRows(const css::uno::Sequence<Any>& rows) override; + + /// @throws SQLException + /// @throws RuntimeException + void checkColumnIndex(sal_Int32 index); + +private: + using ::cppu::OPropertySetHelper::getFastPropertyValue; +}; +} /* mysqlc */ +} /* connectivity */ +#endif // CONNECTIVITY_SRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx new file mode 100644 index 000000000..2b344843d --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.cxx @@ -0,0 +1,578 @@ +/* -*- 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 "mysqlc_general.hxx" +#include "mysqlc_prepared_resultset.hxx" +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_propertyids.hxx" +#include "mysqlc_resultsetmetadata.hxx" + +#include <sal/log.hxx> + +#include <com/sun/star/sdbc/DataType.hpp> + +#include <stdio.h> + +using namespace connectivity::mysqlc; +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::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; +using ::osl::MutexGuard; + +OUString OPreparedStatement::getImplementationName() +{ + return "com.sun.star.sdbcx.mysqlc.PreparedStatement"; +} + +css::uno::Sequence<OUString> OPreparedStatement::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.PreparedStatement" }; +} + +sal_Bool OPreparedStatement::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +OPreparedStatement::OPreparedStatement(OConnection* _pConnection, MYSQL_STMT* pStmt) + : OCommonStatement(_pConnection) + , m_pStmt(pStmt) +{ + m_paramCount = mysql_stmt_param_count(m_pStmt); + m_binds.reserve(m_paramCount); + m_bindMetas.reserve(m_paramCount); + for (unsigned i = 0; i < m_paramCount; ++i) + { + m_binds.push_back(MYSQL_BIND{}); + m_bindMetas.push_back(BindMetaData{}); + m_binds.back().is_null = &m_bindMetas.back().is_null; + m_binds.back().length = &m_bindMetas.back().length; + m_binds.back().buffer = nullptr; + } +} + +OPreparedStatement::~OPreparedStatement() {} + +void SAL_CALL OPreparedStatement::acquire() throw() { OCommonStatement::acquire(); } + +void SAL_CALL OPreparedStatement::release() throw() { OCommonStatement::release(); } + +Any SAL_CALL OPreparedStatement::queryInterface(const Type& rType) +{ + Any aRet = OCommonStatement::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OPreparedStatement_BASE::queryInterface(rType); + } + return aRet; +} + +Sequence<Type> SAL_CALL OPreparedStatement::getTypes() +{ + return concatSequences(OPreparedStatement_BASE::getTypes(), OCommonStatement::getTypes()); +} + +Reference<XResultSetMetaData> SAL_CALL OPreparedStatement::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + + if (!m_xMetaData.is()) + { + MYSQL_RES* pRes = mysql_stmt_result_metadata(m_pStmt); + // TODO warning or error if no meta data. + m_xMetaData = new OResultSetMetaData(*m_xConnection, pRes); + } + return m_xMetaData; +} + +void SAL_CALL OPreparedStatement::close() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + + if (mysql_stmt_close(m_pStmt)) + { + SAL_WARN("connectivity.mysqlc", "failed to close mysql prepared statement"); + } + m_pStmt = nullptr; // it's deallocated already + clearWarnings(); + clearParameters(); + OCommonStatement::close(); +} + +sal_Bool SAL_CALL OPreparedStatement::execute() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + + if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data())) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + int nFail = mysql_stmt_execute(m_pStmt); + if (nFail != 0) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + return !nFail; +} + +sal_Int32 SAL_CALL OPreparedStatement::executeUpdate() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + + if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data())) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + int nFail = mysql_stmt_execute(m_pStmt); + + if (nFail != 0) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + sal_Int32 affectedRows = mysql_stmt_affected_rows(m_pStmt); + return affectedRows; +} + +void SAL_CALL OPreparedStatement::setString(sal_Int32 parameter, const OUString& x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + OString stringie(OUStringToOString(x, m_xConnection->getConnectionEncoding())); + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_STRING; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, stringie.getStr(), MYSQL_TYPE_STRING, + stringie.getLength()); + m_bindMetas[nIndex].is_null = false; + m_bindMetas[nIndex].length = stringie.getLength(); +} + +Reference<XConnection> SAL_CALL OPreparedStatement::getConnection() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + + return m_xConnection.get(); +} + +Reference<XResultSet> SAL_CALL OPreparedStatement::executeQuery() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + + if (!m_binds.empty() && mysql_stmt_bind_param(m_pStmt, m_binds.data())) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + int nFail = mysql_stmt_execute(m_pStmt); + + if (nFail != 0) + { + MYSQL* pMysql = m_xConnection->getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_stmt_error(m_pStmt), + mysql_sqlstate(pMysql), mysql_errno(pMysql), + *this, m_xConnection->getConnectionEncoding()); + } + + Reference<XResultSet> xResultSet = new OPreparedResultSet(*m_xConnection, this, m_pStmt); + return xResultSet; +} + +void SAL_CALL OPreparedStatement::setBoolean(sal_Int32 parameter, sal_Bool x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_TINY; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_TINY); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setByte(sal_Int32 parameter, sal_Int8 x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_TINY; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_TINY); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setDate(sal_Int32 parameter, const Date& aData) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + MYSQL_TIME my_time = {}; + + my_time.year = aData.Year; + my_time.month = aData.Month; + my_time.day = aData.Day; + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_DATE; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_DATE); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setTime(sal_Int32 parameter, const Time& aVal) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + MYSQL_TIME my_time = {}; + + my_time.hour = aVal.Hours; + my_time.minute = aVal.Minutes; + my_time.second = aVal.Seconds; + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_TIME; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_TIME); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setTimestamp(sal_Int32 parameter, const DateTime& aVal) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + MYSQL_TIME my_time = {}; + + my_time.hour = aVal.Hours; + my_time.minute = aVal.Minutes; + my_time.second = aVal.Seconds; + my_time.year = aVal.Year; + my_time.month = aVal.Month; + my_time.day = aVal.Day; + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_DATETIME; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &my_time, MYSQL_TYPE_DATETIME); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setDouble(sal_Int32 parameter, double x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_DOUBLE; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_DOUBLE); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setFloat(sal_Int32 parameter, float x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_FLOAT; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_FLOAT); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setInt(sal_Int32 parameter, sal_Int32 x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_LONG; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_LONG); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setLong(sal_Int32 parameter, sal_Int64 aVal) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_LONGLONG; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &aVal, MYSQL_TYPE_LONGLONG); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setNull(sal_Int32 parameter, sal_Int32 /*sqlType*/) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_bindMetas[nIndex].is_null = true; + free(m_binds[nIndex].buffer); + m_binds[nIndex].buffer = nullptr; +} + +void SAL_CALL OPreparedStatement::setClob(sal_Int32 parameter, const Reference<XClob>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setClob", *this); +} + +void SAL_CALL OPreparedStatement::setBlob(sal_Int32 parameter, const Reference<XBlob>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBlob", *this); +} + +void SAL_CALL OPreparedStatement::setArray(sal_Int32 parameter, const Reference<XArray>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setArray", *this); +} + +void SAL_CALL OPreparedStatement::setRef(sal_Int32 parameter, const Reference<XRef>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setRef", *this); +} + +void SAL_CALL OPreparedStatement::setObjectWithInfo(sal_Int32 parameterIndex, const Any& value, + sal_Int32 targetSqlType, sal_Int32 /* scale */) +{ + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkParameterIndex(parameterIndex); + + const sal_Int32 nIndex = parameterIndex - 1; + if (!value.hasValue()) + { + free(m_binds[nIndex].buffer); + m_binds[nIndex].buffer = nullptr; + m_bindMetas[parameterIndex - 1].is_null = true; + return; + } + + switch (targetSqlType) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + { + double nValue(0.0); + OUString sValue; + if (value >>= nValue) + { + setDouble(parameterIndex, nValue); + break; + } + else if (value >>= sValue) + { + OString sAscii + = OUStringToOString(sValue, getOwnConnection()->getConnectionEncoding()); + std::stringstream sStream{ sAscii.getStr() }; + sStream >> nValue; + m_binds[nIndex].buffer_type = MYSQL_TYPE_DOUBLE; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &nValue, MYSQL_TYPE_DOUBLE, + sValue.getLength()); + m_bindMetas[nIndex].is_null = false; + break; + } + + [[fallthrough]]; + } + + // TODO other types + + default: + mysqlc_sdbc_driver::throwInvalidArgumentException( + "OPreparedStatement::setObjectWithInfo", *this); + break; + } +} + +void SAL_CALL OPreparedStatement::setObjectNull(sal_Int32 parameter, sal_Int32 /* sqlType */, + const OUString& /* typeName */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObjectNull", + *this); +} + +void SAL_CALL OPreparedStatement::setObject(sal_Int32 parameter, const Any& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setObject", *this); +} + +void SAL_CALL OPreparedStatement::setShort(sal_Int32 parameter, sal_Int16 x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_SHORT; + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_SHORT); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setBytes(sal_Int32 parameter, const Sequence<sal_Int8>& x) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + const sal_Int32 nIndex = parameter - 1; + m_binds[nIndex].buffer_type = MYSQL_TYPE_BLOB; // FIXME + mysqlc_sdbc_driver::resetSqlVar(&m_binds[nIndex].buffer, &x, MYSQL_TYPE_BLOB); + m_bindMetas[nIndex].is_null = false; +} + +void SAL_CALL OPreparedStatement::setCharacterStream(sal_Int32 parameter, + const Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException( + "OPreparedStatement::setCharacterStream", *this); +} + +void SAL_CALL OPreparedStatement::setBinaryStream(sal_Int32 parameter, + const Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + checkParameterIndex(parameter); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::setBinaryStream", + *this); +} + +void SAL_CALL OPreparedStatement::clearParameters() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OPreparedStatement::rBHelper.bDisposed); + + for (size_t i = 0; i < m_binds.size(); ++i) + { + m_bindMetas[i].is_null = true; + free(m_binds[i].buffer); + m_binds[i].buffer = nullptr; + } +} + +// void SAL_CALL OPreparedStatement::clearBatch() +// { +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::clearBatch", +// *this); +// } + +// void SAL_CALL OPreparedStatement::addBatch() +// { +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::addBatch", *this); +// } + +// Sequence<sal_Int32> SAL_CALL OPreparedStatement::executeBatch() { +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedStatement::executeBatch", *this); +// } + +void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) +{ + switch (nHandle) + { + case PROPERTY_ID_RESULTSETCONCURRENCY: + break; + case PROPERTY_ID_RESULTSETTYPE: + break; + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_USEBOOKMARKS: + break; + default: + /* XXX: Recursion ?? */ + OPreparedStatement::setFastPropertyValue_NoBroadcast(nHandle, rValue); + } +} + +void OPreparedStatement::checkParameterIndex(sal_Int32 column) +{ + if (column < 1 || column > static_cast<sal_Int32>(m_paramCount)) + { + throw SQLException("Parameter index out of range", *this, OUString(), 1, Any()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx new file mode 100644 index 000000000..0177b15db --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_preparedstatement.hxx @@ -0,0 +1,161 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_PREPAREDSTATEMENT_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_PREPAREDSTATEMENT_HXX +#include "mysqlc_statement.hxx" +#include "mysqlc_resultset.hxx" + +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <cppuhelper/compbase4.hxx> + +namespace connectivity +{ +namespace mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::sdbc::XResultSetMetaData; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Type; + +#if defined MYSQL_VERSION_ID && (MYSQL_VERSION_ID >= 80000) && !defined MARIADB_BASE_VERSION +using my_bool = bool; +#else +using my_bool = char; +#endif + +struct BindMetaData +{ + my_bool is_null = false; + unsigned long length = 0; + my_bool error = false; +}; + +typedef ::cppu::ImplHelper4<css::sdbc::XPreparedStatement, css::sdbc::XParameters, + css::sdbc::XResultSetMetaDataSupplier, css::lang::XServiceInfo> + OPreparedStatement_BASE; + +class OPreparedStatement final : public OCommonStatement, public OPreparedStatement_BASE +{ + unsigned int m_paramCount = 0; // number of placeholders + Reference<XResultSetMetaData> m_xMetaData; + MYSQL_STMT* m_pStmt; + std::vector<MYSQL_BIND> m_binds; + std::vector<BindMetaData> m_bindMetas; + + void checkParameterIndex(sal_Int32 parameter); + + void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override; + virtual ~OPreparedStatement() override; + +public: + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + OPreparedStatement(OConnection* _pConnection, MYSQL_STMT* pStmt); + + //XInterface + Any SAL_CALL queryInterface(const Type& rType) override; + void SAL_CALL acquire() throw() override; + void SAL_CALL release() throw() override; + + //XTypeProvider + css::uno::Sequence<Type> SAL_CALL getTypes() override; + + // XPreparedStatement + Reference<css::sdbc::XResultSet> SAL_CALL executeQuery() override; + sal_Int32 SAL_CALL executeUpdate() override; + sal_Bool SAL_CALL execute() override; + Reference<css::sdbc::XConnection> SAL_CALL getConnection() override; + + // XParameters + void SAL_CALL setNull(sal_Int32 parameter, sal_Int32 sqlType) override; + + void SAL_CALL setObjectNull(sal_Int32 parameter, sal_Int32 sqlType, + const OUString& typeName) override; + + void SAL_CALL setBoolean(sal_Int32 parameter, sal_Bool x) override; + + void SAL_CALL setByte(sal_Int32 parameter, sal_Int8 x) override; + + void SAL_CALL setShort(sal_Int32 parameter, sal_Int16 x) override; + + void SAL_CALL setInt(sal_Int32 parameter, sal_Int32 x) override; + + void SAL_CALL setLong(sal_Int32 parameter, sal_Int64 x) override; + + void SAL_CALL setFloat(sal_Int32 parameter, float x) override; + + void SAL_CALL setDouble(sal_Int32 parameter, double x) override; + + void SAL_CALL setString(sal_Int32 parameter, const OUString& x) override; + + void SAL_CALL setBytes(sal_Int32 parameter, const css::uno::Sequence<sal_Int8>& x) override; + + void SAL_CALL setDate(sal_Int32 parameter, const css::util::Date& x) override; + + void SAL_CALL setTime(sal_Int32 parameter, const css::util::Time& x) override; + void SAL_CALL setTimestamp(sal_Int32 parameter, const css::util::DateTime& x) override; + + void SAL_CALL setBinaryStream(sal_Int32 parameter, const Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + + void SAL_CALL setCharacterStream(sal_Int32 parameter, const Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + + void SAL_CALL setObject(sal_Int32 parameter, const Any& x) override; + + void SAL_CALL setObjectWithInfo(sal_Int32 parameter, const Any& x, sal_Int32 targetSqlType, + sal_Int32 scale) override; + + void SAL_CALL setRef(sal_Int32 parameter, const Reference<css::sdbc::XRef>& x) override; + + void SAL_CALL setBlob(sal_Int32 parameter, const Reference<css::sdbc::XBlob>& x) override; + + void SAL_CALL setClob(sal_Int32 parameter, const Reference<css::sdbc::XClob>& x) override; + + void SAL_CALL setArray(sal_Int32 parameter, const Reference<css::sdbc::XArray>& x) override; + + void SAL_CALL clearParameters() override; + + // XPreparedBatchExecution + // void SAL_CALL addBatch() override; + // void SAL_CALL clearBatch() override; + // css::uno::Sequence<sal_Int32> SAL_CALL executeBatch() override; + + // XCloseable + void SAL_CALL close() override; + + // XResultSetMetaDataSupplier + Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override; +}; +} /* mysqlc */ +} /* connectivity */ +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_PREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx b/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx new file mode 100644 index 000000000..b2c1a1be0 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_propertyids.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_PROPERTYIDS_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_PROPERTYIDS_HXX + +// this define has to be set to split the names into different dll's or so's +// every dll has his own set of property names + +namespace connectivity +{ +namespace mysqlc +{ +enum +{ + PROPERTY_ID_QUERYTIMEOUT = 1, + PROPERTY_ID_MAXFIELDSIZE, + PROPERTY_ID_MAXROWS, + PROPERTY_ID_CURSORNAME, + PROPERTY_ID_RESULTSETCONCURRENCY, + PROPERTY_ID_RESULTSETTYPE, + PROPERTY_ID_FETCHDIRECTION, + PROPERTY_ID_FETCHSIZE, + PROPERTY_ID_ESCAPEPROCESSING, + PROPERTY_ID_USEBOOKMARKS, + PROPERTY_ID_ISBOOKMARKABLE +}; +} /* mysqlc */ +} /* connectivity */ + +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_PROPERTYIDS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx new file mode 100644 index 000000000..75c229823 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx @@ -0,0 +1,1114 @@ +/* -*- 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 "mysqlc_propertyids.hxx" +#include "mysqlc_general.hxx" +#include "mysqlc_resultset.hxx" +#include "mysqlc_resultsetmetadata.hxx" + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/seqstream.hxx> + +using namespace rtl; + +using namespace connectivity::mysqlc; +using namespace cppu; +using namespace com::sun::star; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; +using namespace ::comphelper; +using ::osl::MutexGuard; + +namespace +{ +// copied from string misc, it should be replaced when library is not an +// extension anymore +std::vector<OString> lcl_split(const OString& rStr, char cSeparator) +{ + std::vector<OString> vec; + sal_Int32 idx = 0; + do + { + OString kw = rStr.getToken(0, cSeparator, idx); + kw = kw.trim(); + if (!kw.isEmpty()) + { + vec.push_back(kw); + } + } while (idx >= 0); + return vec; +} +} + +void OResultSet::checkRowIndex() +{ + if (m_nRowPosition < 0 || m_nRowPosition >= m_nRowCount) + { + throw SQLException("Cursor position out of range", *this, OUString(), 1, Any()); + } +} + +bool OResultSet::checkNull(sal_Int32 column) +{ + if (m_aRows[m_nRowPosition][column - 1].isEmpty()) + { + m_bWasNull = true; + return true; + } + m_bWasNull = false; + return false; +} + +OUString SAL_CALL OResultSet::getImplementationName() +{ + return "com.sun.star.sdbcx.mysqlc.ResultSet"; +} + +uno::Sequence<OUString> SAL_CALL OResultSet::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL OResultSet::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +OResultSet::OResultSet(OConnection& rConn, OCommonStatement* pStmt, MYSQL_RES* pResult, + rtl_TextEncoding _encoding) + : OResultSet_BASE(m_aMutex) + , OPropertySetHelper(OResultSet_BASE::rBHelper) + , m_pMysql(rConn.getMysqlConnection()) + , m_aStatement(static_cast<OWeakObject*>(pStmt)) + , m_pResult(pResult) + , m_encoding(_encoding) +{ + assert(m_pResult); + m_xMetaData = new OResultSetMetaData(rConn, m_pResult); +} + +void OResultSet::ensureResultFetched() +{ + if (m_pResult) + { + fetchResult(); + } +} + +void OResultSet::ensureFieldInfoFetched() +{ + if (m_pResult == nullptr) + return; // already fetched + + // it works only if result set is produced via mysql_store_result + // TODO ensure that + m_nRowCount = mysql_num_rows(m_pResult); + + if (!m_aFields.empty()) + return; + unsigned nFieldCount = mysql_num_fields(m_pResult); + MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult); + m_aFields.reserve(nFieldCount); + for (unsigned i = 0; i < nFieldCount; ++i) + m_aFields.push_back(OUString{ + pFields[i].name, static_cast<sal_Int32>(strlen(pFields[i].name)), m_encoding }); +} + +void OResultSet::fetchResult() +{ + // Mysql C API does not allow simultaneously opened result sets, but sdbc does. + // Because of that we need to fetch all of the data ASAP + ensureFieldInfoFetched(); + + // fetch all the data + m_aRows.reserve(m_nRowCount); + + for (sal_Int32 row = 0; row < m_nRowCount; ++row) + { + MYSQL_ROW data = mysql_fetch_row(m_pResult); + unsigned long* lengths = mysql_fetch_lengths(m_pResult); + m_aRows.push_back(DataFields{}); + // MYSQL_ROW is char**, array of strings + for (std::size_t col = 0; col < m_aFields.size(); ++col) + { + m_aRows.back().push_back(OString{ data[col], static_cast<sal_Int32>(lengths[col]) }); + } + } + unsigned errorNum = mysql_errno(m_pMysql); + if (errorNum) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + mysql_error(m_pMysql), mysql_sqlstate(m_pMysql), errorNum, *this, m_encoding); + mysql_free_result(m_pResult); + m_pResult = nullptr; +} + +void OResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + MutexGuard aGuard(m_aMutex); + + if (m_pResult != nullptr) + { + mysql_free_result(m_pResult); + m_pResult = nullptr; + } + m_aStatement = nullptr; + m_xMetaData = nullptr; +} + +Any SAL_CALL OResultSet::queryInterface(const Type& rType) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OResultSet_BASE::queryInterface(rType); + } + return aRet; +} + +uno::Sequence<Type> SAL_CALL OResultSet::getTypes() +{ + OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return concatSequences(aTypes.getTypes(), OResultSet_BASE::getTypes()); +} + +sal_Int32 SAL_CALL OResultSet::findColumn(const OUString& columnName) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + for (std::size_t i = 0; i < m_aFields.size(); ++i) + { + if (columnName.equalsIgnoreAsciiCase(m_aFields[i])) + return static_cast<sal_Int32>(i) + 1; // sdbc indexes from 1 + } + + throw SQLException("The column name '" + columnName + "' is not valid.", *this, "42S22", 0, + Any()); +} + +uno::Reference<XInputStream> SAL_CALL OResultSet::getBinaryStream(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return nullptr; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return new SequenceInputStream{ uno::Sequence<sal_Int8>( + reinterpret_cast<sal_Int8 const*>(sVal.getStr()), getDataLength(column)) }; +} + +uno::Reference<XInputStream> SAL_CALL OResultSet::getCharacterStream(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getCharacterStream", + *this); + return nullptr; +} + +sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return false; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toInt32() != 0; +} + +sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + + return static_cast<sal_Int8>(sVal.toInt32()); +} + +uno::Sequence<sal_Int8> SAL_CALL OResultSet::getBytes(sal_Int32 column) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkBordersAndEnsureFetched(column); + OString sVal = m_aRows[m_nRowPosition][column - 1]; + if (checkNull(column)) + return uno::Sequence<sal_Int8>(); + + return uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const*>(sVal.getStr()), + getDataLength(column)); +} + +Date SAL_CALL OResultSet::getDate(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + Date d; + + if (checkNull(column)) + return d; + + OString dateStr = m_aRows[m_nRowPosition][column - 1]; + + OString dateString(dateStr); + OString token; + sal_Int32 nIndex = 0, i = 0; + do + { + token = dateString.getToken(0, '-', nIndex); + switch (i) + { + case 0: + d.Year = static_cast<sal_uInt16>(token.toUInt32()); + break; + case 1: + d.Month = static_cast<sal_uInt16>(token.toUInt32()); + break; + case 2: + d.Day = static_cast<sal_uInt16>(token.toUInt32()); + break; + default:; + } + i++; + } while (nIndex >= 0); + return d; +} + +double SAL_CALL OResultSet::getDouble(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + if (checkNull(column)) + return 0.0; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toDouble(); +} + +float SAL_CALL OResultSet::getFloat(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0.0f; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toFloat(); +} + +sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toInt32(); +} + +sal_Int32 SAL_CALL OResultSet::getRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nRowPosition + 1; // indexed from 1 +} + +sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0LL; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toInt64(); +} + +uno::Reference<XResultSetMetaData> SAL_CALL OResultSet::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_xMetaData; +} + +uno::Reference<XArray> SAL_CALL OResultSet::getArray(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getArray", *this); + return nullptr; +} + +uno::Reference<XClob> SAL_CALL OResultSet::getClob(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getClob", *this); + return nullptr; +} + +uno::Reference<XBlob> SAL_CALL OResultSet::getBlob(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBlob", *this); + return nullptr; +} + +uno::Reference<XRef> SAL_CALL OResultSet::getRef(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getRef", *this); + return nullptr; +} + +Any SAL_CALL OResultSet::getObject(sal_Int32 column, + const uno::Reference<XNameAccess>& /* typeMap */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getObject", *this); + return Any(); +} + +sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return 0; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return sVal.toInt32(); +} + +OUString SAL_CALL OResultSet::getString(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); + if (checkNull(column)) + return rtl::OUString{}; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + return OStringToOUString(sVal, m_encoding); +} + +Time SAL_CALL OResultSet::getTime(sal_Int32 column) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkBordersAndEnsureFetched(column); + + Time t; + if (checkNull(column)) + return t; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + OString timeString{ sVal.getStr(), getDataLength(column) }; + OString token; + sal_Int32 nIndex, i = 0; + + nIndex = timeString.indexOf(' ') + 1; + do + { + token = timeString.getToken(0, ':', nIndex); + switch (i) + { + case 0: + t.Hours = static_cast<sal_uInt16>(token.toUInt32()); + break; + case 1: + t.Minutes = static_cast<sal_uInt16>(token.toUInt32()); + break; + case 2: + t.Seconds = static_cast<sal_uInt16>(token.toUInt32()); + break; + } + i++; + } while (nIndex >= 0); + + return t; +} + +DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 column) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkBordersAndEnsureFetched(column); + + if (checkNull(column)) + return DateTime{}; + + OString sVal = m_aRows[m_nRowPosition][column - 1]; + + // YY-MM-DD HH:MM:SS + std::vector<OString> dateAndTime + = lcl_split(OString{ sVal.getStr(), getDataLength(column) }, ' '); + + auto dateParts = lcl_split(dateAndTime.at(0), '-'); + auto timeParts = lcl_split(dateAndTime.at(1), ':'); + + if (dateParts.size() < 2 || timeParts.size() < 2) + throw SQLException("Timestamp has a wrong format", *this, OUString(), 1, Any()); + + DateTime dt; + + dt.Year = dateParts.at(0).toUInt32(); + dt.Month = dateParts.at(1).toUInt32(); + dt.Day = dateParts.at(2).toUInt32(); + dt.Hours = timeParts.at(0).toUInt32(); + dt.Minutes = timeParts.at(1).toUInt32(); + dt.Seconds = timeParts.at(2).toUInt32(); + return dt; +} + +sal_Bool SAL_CALL OResultSet::isBeforeFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nRowPosition < 0; +} + +sal_Bool SAL_CALL OResultSet::isAfterLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + return m_nRowPosition >= m_nRowCount; +} + +sal_Bool SAL_CALL OResultSet::isFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + return m_nRowPosition == 0 && !isAfterLast(); +} + +sal_Bool SAL_CALL OResultSet::isLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + return m_nRowPosition == m_nRowCount - 1; +} + +void SAL_CALL OResultSet::beforeFirst() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + m_nRowPosition = -1; +} + +void SAL_CALL OResultSet::afterLast() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + m_nRowPosition = m_nRowCount; +} + +void SAL_CALL OResultSet::close() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (m_pResult != nullptr) + { + mysql_free_result(m_pResult); + m_pResult = nullptr; + } + dispose(); +} + +sal_Bool SAL_CALL OResultSet::first() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + m_nRowPosition = 0; + + return true; +} + +sal_Bool SAL_CALL OResultSet::last() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + m_nRowPosition = m_nRowCount - 1; + + return true; +} + +sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + sal_Int32 nToGo = row < 0 ? (m_nRowCount - 1) - row : row - 1; + + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; + if (nToGo < 0) + nToGo = 0; + + m_nRowPosition = nToGo; + + return true; +} + +sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + + if (row == 0) + return true; + + sal_Int32 nToGo = m_nRowPosition + row; + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; + if (nToGo < 0) + nToGo = 0; + + m_nRowPosition = nToGo; + + return true; +} + +sal_Bool SAL_CALL OResultSet::previous() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if (m_nRowPosition == 0) + { + m_nRowPosition--; + return false; + } + else if (m_nRowPosition < 0) + { + return false; + } + + m_nRowPosition--; + return true; +} + +uno::Reference<uno::XInterface> SAL_CALL OResultSet::getStatement() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_aStatement.get(); +} + +sal_Bool SAL_CALL OResultSet::rowDeleted() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OResultSet::rowInserted() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OResultSet::rowUpdated() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OResultSet::next() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); + if (m_nRowPosition + 1 > m_nRowCount) // afterlast + return false; + if (m_nRowPosition + 1 == m_nRowCount) // last + { + // return false but take it to afterlast anyway + ++m_nRowPosition; + return false; + } + ++m_nRowPosition; + return true; +} + +sal_Bool SAL_CALL OResultSet::wasNull() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + +void SAL_CALL OResultSet::cancel() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OResultSet::clearWarnings() {} + +Any SAL_CALL OResultSet::getWarnings() { return Any(); } + +void SAL_CALL OResultSet::insertRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + // you only have to implement this if you want to insert new rows + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::insertRow", *this); +} + +void SAL_CALL OResultSet::updateRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // only when you allow updates + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateRow", *this); +} + +void SAL_CALL OResultSet::deleteRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::deleteRow", *this); +} + +void SAL_CALL OResultSet::cancelRowUpdates() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::cancelRowUpdates", *this); +} + +void SAL_CALL OResultSet::moveToInsertRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // only when you allow insert's + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::moveToInsertRow", *this); +} + +void SAL_CALL OResultSet::moveToCurrentRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); +} + +void SAL_CALL OResultSet::updateNull(sal_Int32 column) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateNull", *this); +} + +void SAL_CALL OResultSet::updateBoolean(sal_Int32 column, sal_Bool /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBoolean", *this); +} + +void SAL_CALL OResultSet::updateByte(sal_Int32 column, sal_Int8 /* x */) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateByte", *this); +} + +void SAL_CALL OResultSet::updateShort(sal_Int32 column, sal_Int16 /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateShort", *this); +} + +void SAL_CALL OResultSet::updateInt(sal_Int32 column, sal_Int32 /* x */) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + MutexGuard aGuard(m_aMutex); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateInt", *this); +} + +void SAL_CALL OResultSet::updateLong(sal_Int32 column, sal_Int64 /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateLong", *this); +} + +void SAL_CALL OResultSet::updateFloat(sal_Int32 column, float /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateFloat", *this); +} + +void SAL_CALL OResultSet::updateDouble(sal_Int32 column, double /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateDouble", *this); +} + +void SAL_CALL OResultSet::updateString(sal_Int32 column, const OUString& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateString", *this); +} + +void SAL_CALL OResultSet::updateBytes(sal_Int32 column, const uno::Sequence<sal_Int8>& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBytes", *this); +} + +void SAL_CALL OResultSet::updateDate(sal_Int32 column, const Date& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateDate", *this); +} + +void SAL_CALL OResultSet::updateTime(sal_Int32 column, const Time& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateTime", *this); +} + +void SAL_CALL OResultSet::updateTimestamp(sal_Int32 column, const DateTime& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateTimestamp", *this); +} + +void SAL_CALL OResultSet::updateBinaryStream(sal_Int32 column, + const uno::Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateBinaryStream", + *this); +} + +void SAL_CALL OResultSet::updateCharacterStream(sal_Int32 column, + const uno::Reference<XInputStream>& /* x */, + sal_Int32 /* length */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateCharacterStream", + *this); +} + +void SAL_CALL OResultSet::refreshRow() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::refreshRow", *this); +} + +void SAL_CALL OResultSet::updateObject(sal_Int32 column, const Any& /* x */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateObject", *this); +} + +void SAL_CALL OResultSet::updateNumericObject(sal_Int32 column, const Any& /* x */, + sal_Int32 /* scale */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkColumnIndex(column); + checkRowIndex(); + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::updateNumericObject", + *this); +} + +// XRowLocate +Any SAL_CALL OResultSet::getBookmark() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + // if you don't want to support bookmark you must remove the XRowLocate interface + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBookmark", *this); + + return Any(); +} + +sal_Bool SAL_CALL OResultSet::moveToBookmark(const Any& /* bookmark */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return false; +} + +sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark(const Any& /* bookmark */, + sal_Int32 /* rows */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::moveRelativeToBookmark", + *this); + return false; +} + +sal_Int32 SAL_CALL OResultSet::compareBookmarks(const Any& /* n1 */, const Any& /* n2 */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::compareBookmarks", *this); + + return CompareBookmark::NOT_EQUAL; +} + +sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks() { return false; } + +sal_Int32 SAL_CALL OResultSet::hashBookmark(const Any& /* bookmark */) +{ + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::hashBookmark", *this); + return 0; +} + +// XDeleteRows +uno::Sequence<sal_Int32> SAL_CALL OResultSet::deleteRows(const uno::Sequence<Any>& /* rows */) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::deleteRows", *this); + return uno::Sequence<sal_Int32>(); +} + +IPropertyArrayHelper* OResultSet::createArrayHelper() const +{ + uno::Sequence<Property> aProps(5); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = Property("FetchDirection", PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] + = Property("FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = Property("IsBookmarkable", PROPERTY_ID_ISBOOKMARKABLE, + cppu::UnoType<bool>::get(), PropertyAttribute::READONLY); + pProperties[nPos++] = Property("ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + pProperties[nPos++] = Property("ResultSetType", PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + return new OPropertyArrayHelper(aProps); +} + +IPropertyArrayHelper& OResultSet::getInfoHelper() { return *getArrayHelper(); } + +sal_Bool OResultSet::convertFastPropertyValue(Any& /* rConvertedValue */, Any& /* rOldValue */, + sal_Int32 nHandle, const Any& /* rValue */) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + default:; + } + return false; +} + +void OResultSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& /* rValue */) +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw uno::Exception("cannot set prop " + OUString::number(nHandle), nullptr); + case PROPERTY_ID_FETCHDIRECTION: + break; + case PROPERTY_ID_FETCHSIZE: + break; + default:; + } +} + +void OResultSet::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + _rValue <<= false; + break; + case PROPERTY_ID_CURSORNAME: + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + _rValue <<= ResultSetConcurrency::READ_ONLY; + break; + case PROPERTY_ID_RESULTSETTYPE: + _rValue <<= ResultSetType::SCROLL_INSENSITIVE; + break; + case PROPERTY_ID_FETCHDIRECTION: + _rValue <<= FetchDirection::FORWARD; + break; + case PROPERTY_ID_FETCHSIZE: + _rValue <<= sal_Int32(50); + break; + ; + default:; + } +} + +void SAL_CALL OResultSet::acquire() throw() { OResultSet_BASE::acquire(); } + +void SAL_CALL OResultSet::release() throw() { OResultSet_BASE::release(); } + +css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL OResultSet::getPropertySetInfo() +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +void OResultSet::checkColumnIndex(sal_Int32 index) +{ + if (index < 1 || index > static_cast<int>(m_aFields.size())) + { + /* static object for efficiency or thread safety is a problem ? */ + throw SQLException("index out of range", *this, OUString(), 1, Any()); + } +} + +void OResultSet::checkBordersAndEnsureFetched(sal_Int32 index) +{ + ensureResultFetched(); + checkColumnIndex(index); + checkRowIndex(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx new file mode 100644 index 000000000..dca2bb4a9 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx @@ -0,0 +1,279 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_RESULTSET_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_RESULTSET_HXX + +#include "mysqlc_preparedstatement.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_subcomponent.hxx" +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> + +#include <cppuhelper/compbase12.hxx> + +namespace connectivity +{ +namespace mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::RuntimeException; + +/* + ** OResultSet + */ +typedef ::cppu::WeakComponentImplHelper12< + css::sdbc::XResultSet, css::sdbc::XRow, css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, css::sdbc::XWarningsSupplier, css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, css::sdbcx::XRowLocate, css::sdbcx::XDeleteRows, css::sdbc::XCloseable, + css::sdbc::XColumnLocate, css::lang::XServiceInfo> + OResultSet_BASE; + +class OResultSet final : public OBase_Mutex, + public OResultSet_BASE, + public ::cppu::OPropertySetHelper, + public OPropertyArrayUsageHelper<OResultSet> +{ + using DataFields = std::vector<OString>; + std::vector<DataFields> m_aRows; + std::vector<OUString> m_aFields; + MYSQL* m_pMysql = nullptr; + css::uno::WeakReferenceHelper m_aStatement; + css::uno::Reference<css::sdbc::XResultSetMetaData> m_xMetaData; + MYSQL_RES* m_pResult; + rtl_TextEncoding m_encoding; + bool m_bWasNull = false; // did the last getXXX result null? + + sal_Int32 getDataLength(sal_Int32 column) + { + return m_aRows[m_nRowPosition][column - 1].getLength(); + } + bool checkNull(sal_Int32 column); + + /** + * Position of cursor indexed from 0 + */ + sal_Int32 m_nRowPosition = -1; + sal_Int32 m_nRowCount = 0; + + // OPropertyArrayUsageHelper + ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, + sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override; + + virtual ~OResultSet() override = default; + + /** + * Ensures that the results of the query has already been fetched. + */ + void ensureResultFetched(); + + /** + * Ensures that meta data of the corresponding result set has been already + * queried. It should be called before freeing the result set, unless the + * information is lost. + */ + void ensureFieldInfoFetched(); + + /** + * Check the following things: + * - cursor is out of range. Throws exception if true. + * - column index is out of range. Throws exception if true. + * - result set is fetched. If no, then it fetches the result. + */ + void checkBordersAndEnsureFetched(sal_Int32 index); + + /** + * Fetches all the data from the MYSQL_RES object related to the class. It + * frees the MYSQL_RES object afterwards, so it cannot be used anymore. + */ + void fetchResult(); + +public: + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + OResultSet(OConnection& rConn, OCommonStatement* pStmt, MYSQL_RES* pResult, + rtl_TextEncoding _encoding); + + // ::cppu::OComponentHelper + void SAL_CALL disposing() override; + + // XInterface + Any SAL_CALL queryInterface(const css::uno::Type& rType) override; + + void SAL_CALL acquire() throw() override; + void SAL_CALL release() throw() override; + + //XTypeProvider + css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override; + + // XPropertySet + css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + + // XResultSet + sal_Bool SAL_CALL next() override; + sal_Bool SAL_CALL isBeforeFirst() override; + sal_Bool SAL_CALL isAfterLast() override; + sal_Bool SAL_CALL isFirst() override; + sal_Bool SAL_CALL isLast() override; + + void SAL_CALL beforeFirst() override; + void SAL_CALL afterLast() override; + + sal_Bool SAL_CALL first() override; + sal_Bool SAL_CALL last() override; + + sal_Int32 SAL_CALL getRow() override; + + sal_Bool SAL_CALL absolute(sal_Int32 row) override; + sal_Bool SAL_CALL relative(sal_Int32 rows) override; + sal_Bool SAL_CALL previous() override; + + void SAL_CALL refreshRow() override; + + sal_Bool SAL_CALL rowUpdated() override; + sal_Bool SAL_CALL rowInserted() override; + sal_Bool SAL_CALL rowDeleted() override; + + css::uno::Reference<css::uno::XInterface> SAL_CALL getStatement() override; + // XRow + sal_Bool SAL_CALL wasNull() override; + + OUString SAL_CALL getString(sal_Int32 column) override; + + sal_Bool SAL_CALL getBoolean(sal_Int32 column) override; + sal_Int8 SAL_CALL getByte(sal_Int32 column) override; + sal_Int16 SAL_CALL getShort(sal_Int32 column) override; + sal_Int32 SAL_CALL getInt(sal_Int32 column) override; + sal_Int64 SAL_CALL getLong(sal_Int32 column) override; + + float SAL_CALL getFloat(sal_Int32 column) override; + double SAL_CALL getDouble(sal_Int32 column) override; + + css::uno::Sequence<sal_Int8> SAL_CALL getBytes(sal_Int32 column) override; + css::util::Date SAL_CALL getDate(sal_Int32 column) override; + css::util::Time SAL_CALL getTime(sal_Int32 column) override; + css::util::DateTime SAL_CALL getTimestamp(sal_Int32 column) override; + + css::uno::Reference<css::io::XInputStream> SAL_CALL getBinaryStream(sal_Int32 column) override; + css::uno::Reference<css::io::XInputStream> + SAL_CALL getCharacterStream(sal_Int32 column) override; + + Any SAL_CALL getObject( + sal_Int32 column, const css::uno::Reference<css::container::XNameAccess>& typeMap) override; + + css::uno::Reference<css::sdbc::XRef> SAL_CALL getRef(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XBlob> SAL_CALL getBlob(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XClob> SAL_CALL getClob(sal_Int32 column) override; + css::uno::Reference<css::sdbc::XArray> SAL_CALL getArray(sal_Int32 column) override; + + // XResultSetMetaDataSupplier + css::uno::Reference<css::sdbc::XResultSetMetaData> SAL_CALL getMetaData() override; + + // XCancellable + void SAL_CALL cancel() override; + + // XCloseable + void SAL_CALL close() override; + + // XWarningsSupplier + Any SAL_CALL getWarnings() override; + + void SAL_CALL clearWarnings() override; + + // XResultSetUpdate + void SAL_CALL insertRow() override; + void SAL_CALL updateRow() override; + void SAL_CALL deleteRow() override; + void SAL_CALL cancelRowUpdates() override; + void SAL_CALL moveToInsertRow() override; + void SAL_CALL moveToCurrentRow() override; + + // XRowUpdate + void SAL_CALL updateNull(sal_Int32 column) override; + void SAL_CALL updateBoolean(sal_Int32 column, sal_Bool x) override; + void SAL_CALL updateByte(sal_Int32 column, sal_Int8 x) override; + void SAL_CALL updateShort(sal_Int32 column, sal_Int16 x) override; + void SAL_CALL updateInt(sal_Int32 column, sal_Int32 x) override; + void SAL_CALL updateLong(sal_Int32 column, sal_Int64 x) override; + void SAL_CALL updateFloat(sal_Int32 column, float x) override; + void SAL_CALL updateDouble(sal_Int32 column, double x) override; + void SAL_CALL updateString(sal_Int32 column, const OUString& x) override; + void SAL_CALL updateBytes(sal_Int32 column, const css::uno::Sequence<sal_Int8>& x) override; + void SAL_CALL updateDate(sal_Int32 column, const css::util::Date& x) override; + void SAL_CALL updateTime(sal_Int32 column, const css::util::Time& x) override; + void SAL_CALL updateTimestamp(sal_Int32 column, const css::util::DateTime& x) override; + void SAL_CALL updateBinaryStream(sal_Int32 column, + const css::uno::Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + void SAL_CALL updateCharacterStream(sal_Int32 column, + const css::uno::Reference<css::io::XInputStream>& x, + sal_Int32 length) override; + void SAL_CALL updateObject(sal_Int32 column, const Any& x) override; + void SAL_CALL updateNumericObject(sal_Int32 column, const Any& x, sal_Int32 scale) override; + + // XColumnLocate + sal_Int32 SAL_CALL findColumn(const OUString& columnName) override; + + // XRowLocate + Any SAL_CALL getBookmark() override; + + sal_Bool SAL_CALL moveToBookmark(const Any& bookmark) override; + sal_Bool SAL_CALL moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) override; + sal_Int32 SAL_CALL compareBookmarks(const Any& first, const Any& second) override; + sal_Bool SAL_CALL hasOrderedBookmarks() override; + sal_Int32 SAL_CALL hashBookmark(const Any& bookmark) override; + + // XDeleteRows + css::uno::Sequence<sal_Int32> SAL_CALL deleteRows(const css::uno::Sequence<Any>& rows) override; + + void checkColumnIndex(sal_Int32 index); + void checkRowIndex(); + +private: + using ::cppu::OPropertySetHelper::getFastPropertyValue; +}; +} /* mysqlc */ +} /* connectivity */ +#endif // CONNECTIVITY_SRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx new file mode 100644 index 000000000..ab9c2fb39 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx @@ -0,0 +1,211 @@ +/* -*- 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 "mysqlc_resultsetmetadata.hxx" +#include "mysqlc_general.hxx" + +#include <com/sun/star/sdbc/XRow.hpp> +#include <rtl/ustrbuf.hxx> + +using namespace connectivity::mysqlc; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; + +OResultSetMetaData::OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult) + : m_rConnection(rConn) +{ + MYSQL_FIELD* fields = mysql_fetch_field(pResult); + unsigned nFieldCount = mysql_num_fields(pResult); + for (unsigned i = 0; i < nFieldCount; ++i) + { + MySqlFieldInfo fieldInfo; + { + fieldInfo.columnName + = OUString{ fields[i].name, static_cast<sal_Int32>(fields[i].name_length), + m_rConnection.getConnectionEncoding() }; + fieldInfo.length = static_cast<sal_Int32>(fields[i].length); + fieldInfo.type + = mysqlc_sdbc_driver::mysqlToOOOType(fields[i].type, fields[i].charsetnr); + fieldInfo.mysql_type = fields[i].type; + fieldInfo.charsetNumber = fields[i].charsetnr; + fieldInfo.flags = fields[i].flags; + fieldInfo.schemaName + = OUString{ fields[i].db, static_cast<sal_Int32>(fields[i].db_length), + m_rConnection.getConnectionEncoding() }; + fieldInfo.tableName + = OUString{ fields[i].table, static_cast<sal_Int32>(fields[i].table_length), + m_rConnection.getConnectionEncoding() }; + fieldInfo.catalogName + = OUString{ fields[i].catalog, static_cast<sal_Int32>(fields[i].catalog_length), + m_rConnection.getConnectionEncoding() }; + fieldInfo.decimals = static_cast<sal_Int32>(fields[i].decimals); + fieldInfo.max_length = static_cast<sal_Int32>(fields[i].max_length); + } + m_fields.push_back(std::move(fieldInfo)); + } +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).length; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnType(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).type; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount() { return m_fields.size(); } + +sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32 column) +{ + // MYSQL_FIELD::charsetnr is the collation identifier + // _ci postfix means it's insensitive + OUStringBuffer sql{ "SHOW COLLATION WHERE Id =" }; + sql.append(OUString::number(m_fields.at(column - 1).charsetNumber)); + + Reference<XStatement> stmt = m_rConnection.createStatement(); + Reference<XResultSet> rs = stmt->executeQuery(sql.makeStringAndClear()); + Reference<XRow> xRow(rs, UNO_QUERY_THROW); + + if (!rs->next()) // fetch first and only row + return false; + + OUString sColName = xRow->getString(1); // first column is Collation name + + return !sColName.isEmpty() && !sColName.endsWith("_ci"); +} + +OUString SAL_CALL OResultSetMetaData::getSchemaName(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).schemaName; +} + +OUString SAL_CALL OResultSetMetaData::getColumnName(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).columnName; +} + +OUString SAL_CALL OResultSetMetaData::getTableName(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).tableName; +} + +OUString SAL_CALL OResultSetMetaData::getCatalogName(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).catalogName; +} + +OUString SAL_CALL OResultSetMetaData::getColumnTypeName(sal_Int32 column) +{ + checkColumnIndex(column); + return mysqlc_sdbc_driver::mysqlTypeToStr(m_fields.at(column - 1).mysql_type, + m_fields.at(column - 1).flags); +} + +OUString SAL_CALL OResultSetMetaData::getColumnLabel(sal_Int32 column) +{ + checkColumnIndex(column); + return getColumnName(column); +} + +OUString SAL_CALL OResultSetMetaData::getColumnServiceName(sal_Int32 /*column*/) +{ + return OUString{}; +} + +sal_Bool SAL_CALL OResultSetMetaData::isCurrency(sal_Int32 /*column*/) +{ + return false; // TODO +} + +sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement(sal_Int32 column) +{ + checkColumnIndex(column); + return (m_fields.at(column - 1).flags & AUTO_INCREMENT_FLAG) != 0; +} + +sal_Bool SAL_CALL OResultSetMetaData::isSigned(sal_Int32 column) +{ + checkColumnIndex(column); + return !(m_fields.at(column - 1).flags & UNSIGNED_FLAG); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getPrecision(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).max_length - m_fields.at(column - 1).decimals; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getScale(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).decimals; +} + +sal_Int32 SAL_CALL OResultSetMetaData::isNullable(sal_Int32 column) +{ + checkColumnIndex(column); + return (m_fields.at(column - 1).flags & NOT_NULL_FLAG) ? 0 : 1; +} + +sal_Bool SAL_CALL OResultSetMetaData::isSearchable(sal_Int32 column) +{ + checkColumnIndex(column); + return true; +} + +sal_Bool SAL_CALL OResultSetMetaData::isReadOnly(sal_Int32 column) +{ + checkColumnIndex(column); + return m_fields.at(column - 1).schemaName.isEmpty(); +} + +sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable(sal_Int32 column) +{ + checkColumnIndex(column); + return !isReadOnly(column); +} + +sal_Bool SAL_CALL OResultSetMetaData::isWritable(sal_Int32 column) +{ + checkColumnIndex(column); + return !isReadOnly(column); +} + +void OResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex) +{ + auto nColCount = m_fields.size(); + if (columnIndex < 1 || columnIndex > static_cast<sal_Int32>(nColCount)) + { + OUString str = "Column index out of range (expected 1 to " + + OUString::number(sal_Int32(nColCount)) + ", got " + + OUString::number(columnIndex) + "."; + throw SQLException(str, *this, OUString(), 1, Any()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx new file mode 100644 index 000000000..52ca9595b --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx @@ -0,0 +1,109 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_RESULTSETMETADATA_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_RESULTSETMETADATA_HXX + +#include "mysqlc_connection.hxx" + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <cppuhelper/implbase1.hxx> +#include <mysql.h> + +namespace connectivity +{ +namespace mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::RuntimeException; + +struct MySqlFieldInfo +{ + OUString columnName; + sal_Int32 length = 0; + sal_Int32 type = 0; + enum_field_types mysql_type = {}; + unsigned charsetNumber = 0; + unsigned flags = 0; + OUString schemaName; + OUString tableName; + OUString catalogName; + sal_Int32 decimals; + sal_Int32 max_length; +}; + +//************ Class: ResultSetMetaData + +typedef ::cppu::WeakImplHelper1<css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE; + +class OResultSetMetaData final : public OResultSetMetaData_BASE +{ +private: + OConnection& m_rConnection; + std::vector<MySqlFieldInfo> m_fields; + + void checkColumnIndex(sal_Int32 columnIndex); + virtual ~OResultSetMetaData() override = default; + +public: + OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult); + + sal_Int32 SAL_CALL getColumnCount() override; + + sal_Bool SAL_CALL isAutoIncrement(sal_Int32 column) override; + sal_Bool SAL_CALL isCaseSensitive(sal_Int32 column) override; + sal_Bool SAL_CALL isSearchable(sal_Int32 column) override; + sal_Bool SAL_CALL isCurrency(sal_Int32 column) override; + + sal_Int32 SAL_CALL isNullable(sal_Int32 column) override; + + sal_Bool SAL_CALL isSigned(sal_Int32 column) override; + + sal_Int32 SAL_CALL getColumnDisplaySize(sal_Int32 column) override; + + OUString SAL_CALL getColumnLabel(sal_Int32 column) override; + OUString SAL_CALL getColumnName(sal_Int32 column) override; + OUString SAL_CALL getSchemaName(sal_Int32 column) override; + + sal_Int32 SAL_CALL getPrecision(sal_Int32 column) override; + sal_Int32 SAL_CALL getScale(sal_Int32 column) override; + + OUString SAL_CALL getTableName(sal_Int32 column) override; + OUString SAL_CALL getCatalogName(sal_Int32 column) override; + + sal_Int32 SAL_CALL getColumnType(sal_Int32 column) override; + + OUString SAL_CALL getColumnTypeName(sal_Int32 column) override; + + sal_Bool SAL_CALL isReadOnly(sal_Int32 column) override; + sal_Bool SAL_CALL isWritable(sal_Int32 column) override; + sal_Bool SAL_CALL isDefinitelyWritable(sal_Int32 column) override; + + OUString SAL_CALL getColumnServiceName(sal_Int32 column) override; +}; +} +} + +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_RESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_services.cxx b/connectivity/source/drivers/mysqlc/mysqlc_services.cxx new file mode 100644 index 000000000..de611375c --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_services.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 "mysqlc_driver.hxx" + +#include <cppuhelper/factory.hxx> +#include <uno/lbnames.h> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::mysqlc; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +typedef Reference<XSingleServiceFactory> (*createFactoryFunc)( + const Reference<XMultiServiceFactory>& rServiceManager, const OUString& rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, const Sequence<OUString>& rServiceNames, + rtl_ModuleCount*); + +namespace +{ +struct ProviderRequest +{ + Reference<XSingleServiceFactory> xRet; + Reference<XMultiServiceFactory> const xServiceManager; + OUString const sImplementationName; + + ProviderRequest(void* pServiceManager, char const* pImplementationName) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER(const OUString& Implname, const Sequence<OUString>& Services, + ::cppu::ComponentInstantiation Factory, createFactoryFunc creator) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator(xServiceManager, sImplementationName, Factory, Services, nullptr); + } + catch (...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* component_getFactory(const char* pImplementationName, + void* pServiceManager, + void* /* pRegistryKey */) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager, pImplementationName); + + aReq.CREATE_PROVIDER(MysqlCDriver::getImplementationName_Static(), + MysqlCDriver::getSupportedServiceNames_Static(), + MysqlCDriver_CreateInstance, ::cppu::createSingleFactory); + + if (aReq.xRet.is()) + { + aReq.xRet->acquire(); + } + + pRet = aReq.getProvider(); + } + + return pRet; +}; + +extern "C" SAL_DLLPUBLIC_EXPORT void +component_getImplementationEnvironment(char const** ppEnvTypeName, uno_Environment**) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx b/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx new file mode 100644 index 000000000..0082f96b6 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_statement.cxx @@ -0,0 +1,404 @@ +/* -*- 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 "mysqlc_connection.hxx" +#include "mysqlc_propertyids.hxx" +#include "mysqlc_resultset.hxx" +#include "mysqlc_statement.hxx" +#include "mysqlc_general.hxx" + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace connectivity::mysqlc; + +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; +using ::osl::MutexGuard; + +OCommonStatement::OCommonStatement(OConnection* _pConnection) + : OCommonStatement_IBase(m_aMutex) + , OPropertySetHelper(OCommonStatement_IBase::rBHelper) + , m_xConnection(_pConnection) +{ +} + +OCommonStatement::~OCommonStatement() {} + +void OCommonStatement::closeResultSet() +{ + if (m_xResultSet.is()) + { + css::uno::Reference<css::sdbc::XCloseable> xClose(m_xResultSet, UNO_QUERY_THROW); + xClose->close(); + m_xResultSet.clear(); + } +} + +void OCommonStatement::disposing() +{ + MutexGuard aGuard(m_aMutex); + + m_xConnection.clear(); + OCommonStatement_IBase::disposing(); +} + +Any SAL_CALL OCommonStatement::queryInterface(const Type& rType) +{ + Any aRet = OCommonStatement_IBase::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OPropertySetHelper::queryInterface(rType); + } + return aRet; +} + +Sequence<Type> SAL_CALL OCommonStatement::getTypes() +{ + ::cppu::OTypeCollection aTypes(cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return concatSequences(aTypes.getTypes(), OCommonStatement_IBase::getTypes()); +} + +Sequence<Type> SAL_CALL OStatement::getTypes() +{ + return concatSequences(OStatement_BASE::getTypes(), OCommonStatement::getTypes()); +} + +void SAL_CALL OCommonStatement::cancel() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + // cancel the current sql statement +} + +void SAL_CALL OCommonStatement::close() +{ + /* + We need a block for the checkDisposed call. + After the check we can call dispose() as we are not under lock ?? + */ + { + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + } + dispose(); + closeResultSet(); +} + +// void SAL_CALL OStatement::clearBatch() +// { +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution"); +// } + +sal_Bool SAL_CALL OStatement::execute(const OUString& sql) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + closeResultSet(); + m_nAffectedRows = -1; + + OString toExec = OUStringToOString(sql, m_xConnection->getConnectionSettings().encoding); + + MYSQL* pMySql = m_xConnection->getMysqlConnection(); + + // NOTE: differs from MySQL C API, where mysql_real_escape_string_quote() + // should be used. + // toExec = mysqlc_sdbc_driver::escapeSql(toExec); + int failure = mysql_real_query(pMySql, toExec.getStr(), toExec.getLength()); + + if (failure || mysql_errno(pMySql)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMySql), mysql_sqlstate(pMySql), + mysql_errno(pMySql), *this, + m_xConnection->getConnectionEncoding()); + + return getResult(); +} + +Reference<XResultSet> SAL_CALL OStatement::executeQuery(const OUString& sql) +{ + bool isRS(execute(sql)); + // if a MySQL error occurred, it was already thrown and the below is not executed + assert(isRS == m_xResultSet.is()); + if (!isRS) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + "executeQuery called on SQL command that does not return a ResultSet", "02000", 0, + *this); + if (!m_xResultSet.is()) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + "internal MySQL-SDBC error: executeQuery: no ResultSet after execute() returned true.", + "02000", 0, *this); + + return m_xResultSet; +} + +Reference<XConnection> SAL_CALL OStatement::getConnection() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + // just return our connection here + return m_xConnection.get(); +} + +sal_Int32 SAL_CALL OStatement::getUpdateCount() { return m_nAffectedRows; } + +Any SAL_CALL OStatement::queryInterface(const Type& rType) +{ + Any aRet = OCommonStatement::queryInterface(rType); + if (!aRet.hasValue()) + { + aRet = OStatement_BASE::queryInterface(rType); + } + return aRet; +} + +// void SAL_CALL OStatement::addBatch(const OUString&) +// { +// MutexGuard aGuard(m_aMutex); +// checkDisposed(rBHelper.bDisposed); + +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution"); +// } + +// Sequence<sal_Int32> SAL_CALL OStatement::executeBatch() +// { +// MutexGuard aGuard(m_aMutex); +// checkDisposed(rBHelper.bDisposed); + +// mysqlc_sdbc_driver::throwFeatureNotImplementedException("com:sun:star:sdbc:XBatchExecution"); +// } + +sal_Int32 SAL_CALL OStatement::executeUpdate(const OUString& sql) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + execute(sql); + return m_nAffectedRows; +} + +Reference<XResultSet> SAL_CALL OStatement::getResultSet() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + return m_xResultSet; +} + +bool OStatement::getResult() +{ + // all callers already reset that + assert(!m_xResultSet.is()); + assert(m_nAffectedRows == -1); + + MYSQL* pMySql = m_xConnection->getMysqlConnection(); + MYSQL_RES* pMysqlResult = mysql_store_result(pMySql); + if (pMysqlResult != nullptr) + { + // MariaDB/MySQL will return the number of rows in the ResultSet from mysql_affected_rows(); + // sdbc mandates -1 when the command (query) returns a ResultSet + assert(m_nAffectedRows == -1); + m_xResultSet = new OResultSet(*getOwnConnection(), this, pMysqlResult, + m_xConnection->getConnectionEncoding()); + return true; + } + else if (mysql_field_count(pMySql) == 0) + { + m_nAffectedRows = mysql_affected_rows(pMySql); + return false; + } + else + { + mysqlc_sdbc_driver::throwSQLExceptionWithMsg( + "mysql_store_result indicated success and SQL command was supposed to return a " + "ResultSet, but did not.", + "02000", 0, *this); + } + //unreachable + assert(false); + // keep -Werror=return-type happy + return false; +} + +sal_Bool SAL_CALL OStatement::getMoreResults() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + closeResultSet(); + m_nAffectedRows = -1; + + MYSQL* pMySql = m_xConnection->getMysqlConnection(); + int status = mysql_next_result(pMySql); + + if (status > 0 || mysql_errno(pMySql)) + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMySql), mysql_sqlstate(pMySql), + mysql_errno(pMySql), *this, + m_xConnection->getConnectionEncoding()); + + if (status == -1) + return false; + + if (status != 0) + { + const OUString errMsg("mysql_next_result returned unexpected value: " + + OUString::number(status)); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(errMsg, "02000", 0, *this); + } + + return getResult(); +} + +Any SAL_CALL OCommonStatement::getWarnings() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + return makeAny(m_aLastWarning); +} + +void SAL_CALL OCommonStatement::clearWarnings() +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + m_aLastWarning = SQLWarning(); +} + +::cppu::IPropertyArrayHelper* OCommonStatement::createArrayHelper() const +{ + // this properties are define by the service statement + // they must in alphabetic order + Sequence<Property> aProps(10); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] + = Property("CursorName", PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] + = Property("EscapeProcessing", PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0); + pProperties[nPos++] = Property("FetchDirection", PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] + = Property("FetchSize", PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] + = Property("MaxFieldSize", PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] + = Property("MaxRows", PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] + = Property("QueryTimeOut", PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = Property("ResultSetConcurrency", PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] + = Property("ResultSetType", PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] + = Property("UseBookmarks", PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper& OCommonStatement::getInfoHelper() { return *getArrayHelper(); } + +sal_Bool OCommonStatement::convertFastPropertyValue(Any& /* rConvertedValue */, + Any& /* rOldValue */, sal_Int32 /* nHandle */, + const Any& /* rValue */) +{ + // here we have to try to convert + return false; +} + +void OCommonStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& /* rValue */) +{ + // set the value to whatever is necessary + switch (nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + case PROPERTY_ID_USEBOOKMARKS: + default:; + } +} + +void OCommonStatement::getFastPropertyValue(Any& _rValue, sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + case PROPERTY_ID_MAXFIELDSIZE: + case PROPERTY_ID_MAXROWS: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + case PROPERTY_ID_ESCAPEPROCESSING: + break; + case PROPERTY_ID_USEBOOKMARKS: + _rValue <<= false; + break; + default:; + } +} + +OUString OStatement::getImplementationName() { return "com.sun.star.sdbcx.OStatement"; } + +css::uno::Sequence<OUString> OStatement::getSupportedServiceNames() +{ + return { "com.sun.star.sdbc.Statement" }; +} + +sal_Bool OStatement::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +void SAL_CALL OCommonStatement::acquire() throw() { OCommonStatement_IBase::acquire(); } + +void SAL_CALL OCommonStatement::release() throw() { OCommonStatement_IBase::release(); } + +void SAL_CALL OStatement::acquire() throw() { OCommonStatement::acquire(); } + +void SAL_CALL OStatement::release() throw() { OCommonStatement::release(); } + +Reference<css::beans::XPropertySetInfo> SAL_CALL OCommonStatement::getPropertySetInfo() +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx b/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx new file mode 100644 index 000000000..4416ccceb --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_statement.hxx @@ -0,0 +1,180 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_STATEMENT_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_STATEMENT_HXX + +#include "mysqlc_connection.hxx" +#include "mysqlc_subcomponent.hxx" + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XBatchExecution.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/util/XCancellable.hpp> + +#include <cppuhelper/compbase3.hxx> +#include <rtl/ref.hxx> + +namespace connectivity +{ +namespace mysqlc +{ +using ::com::sun::star::sdbc::SQLException; +using ::com::sun::star::sdbc::SQLWarning; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Type; + +typedef ::cppu::WeakComponentImplHelper3<css::sdbc::XWarningsSupplier, css::util::XCancellable, + css::sdbc::XCloseable> + OCommonStatement_IBase; + +//************ Class: OCommonStatement +// is a base class for the normal statement and for the prepared statement + +class OCommonStatement : public OBase_Mutex, + public OCommonStatement_IBase, + public ::cppu::OPropertySetHelper, + public OPropertyArrayUsageHelper<OCommonStatement> + +{ +private: + SQLWarning m_aLastWarning; + +protected: + rtl::Reference<OConnection> m_xConnection; // The owning Connection object + + css::uno::Reference<css::sdbc::XResultSet> m_xResultSet; + + // number of rows affected by an UPDATE, DELETE or INSERT statement. + sal_Int32 m_nAffectedRows = 0; + +protected: + void closeResultSet(); + + // OPropertyArrayUsageHelper + ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + // OPropertySetHelper + ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + sal_Bool SAL_CALL convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, + sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) override; + + void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override; + virtual ~OCommonStatement() override; + +protected: + OCommonStatement(OConnection* _pConnection); + +public: + using OCommonStatement_IBase::rBHelper; + using OCommonStatement_IBase::operator css::uno::Reference<css::uno::XInterface>; + + // OComponentHelper + void SAL_CALL disposing() override; + + // XInterface + void SAL_CALL release() throw() override; + void SAL_CALL acquire() throw() override; + Any SAL_CALL queryInterface(const css::uno::Type& rType) override; + + //XTypeProvider + css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override; + + // XPropertySet + css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + + // XWarningsSupplier + Any SAL_CALL getWarnings() override; + + void SAL_CALL clearWarnings() override; + + // XCancellable + void SAL_CALL cancel() override; + + // XCloseable + void SAL_CALL close() override; + + // other methods + OConnection* getOwnConnection() const { return m_xConnection.get(); } + +private: + using ::cppu::OPropertySetHelper::getFastPropertyValue; +}; + +typedef ::cppu::ImplHelper3<css::lang::XServiceInfo, css::sdbc::XMultipleResults, + css::sdbc::XStatement> + OStatement_BASE; + +class OStatement final : public OCommonStatement, public OStatement_BASE +{ + virtual ~OStatement() override = default; + + bool getResult(); + +public: + // A constructor which is required for the return of the objects + OStatement(OConnection* _pConnection) + : OCommonStatement(_pConnection) + { + } + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + //XInterface + Any SAL_CALL queryInterface(const css::uno::Type& rType) override; + void SAL_CALL acquire() throw() override; + void SAL_CALL release() throw() override; + + //XTypeProvider + css::uno::Sequence<Type> SAL_CALL getTypes() override; + + // XStatement + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL executeQuery(const OUString& sql) override; + sal_Int32 SAL_CALL executeUpdate(const OUString& sql) override; + sal_Bool SAL_CALL execute(const OUString& sql) override; + css::uno::Reference<css::sdbc::XConnection> SAL_CALL getConnection() override; + + // XMultipleResults + css::uno::Reference<css::sdbc::XResultSet> SAL_CALL getResultSet() override; + sal_Int32 SAL_CALL getUpdateCount() override; + sal_Bool SAL_CALL getMoreResults() override; + + // XBatchExecution + // void SAL_CALL addBatch(const OUString& sql) override; + + // void SAL_CALL clearBatch() override; + + // css::uno::Sequence<sal_Int32> SAL_CALL executeBatch() override; +}; +} +} +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_STATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx b/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx new file mode 100644 index 000000000..a1b02da51 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_subcomponent.hxx @@ -0,0 +1,160 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_SUBCOMPONENT_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_SUBCOMPONENT_HXX + +#include <cppuhelper/propshlp.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> + +namespace cppu +{ +class IPropertyArrayHelper; +} + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace lang +{ +class XComponent; +} +} +} +} + +namespace connectivity +{ +namespace mysqlc +{ +/// @throws css::lang::DisposedException +void checkDisposed(bool _bThrow); + +template <class TYPE> class OPropertyArrayUsageHelper +{ +protected: + static sal_Int32 s_nRefCount; + static ::cppu::IPropertyArrayHelper* s_pProps; + static ::osl::Mutex s_aMutex; + +public: + OPropertyArrayUsageHelper(); + virtual ~OPropertyArrayUsageHelper(); + + /** call this in the getInfoHelper method of your derived class. The method returns the array helper of the + class, which is created if necessary. + */ + ::cppu::IPropertyArrayHelper* getArrayHelper(); + +protected: + /** used to implement the creation of the array helper which is shared amongst all instances of the class. + This method needs to be implemented in derived classes. + <BR> + The method gets called with s_aMutex acquired. + @return a pointer to the newly created array helper. Must not be NULL. + */ + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const = 0; +}; + +template <class TYPE> sal_Int32 OPropertyArrayUsageHelper<TYPE>::s_nRefCount = 0; + +template <class TYPE> +::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper<TYPE>::s_pProps = nullptr; + +template <class TYPE>::osl::Mutex OPropertyArrayUsageHelper<TYPE>::s_aMutex; + +template <class TYPE> OPropertyArrayUsageHelper<TYPE>::OPropertyArrayUsageHelper() +{ + ::osl::MutexGuard aGuard(s_aMutex); + ++s_nRefCount; +} + +template <class TYPE> OPropertyArrayUsageHelper<TYPE>::~OPropertyArrayUsageHelper() +{ + ::osl::MutexGuard aGuard(s_aMutex); + OSL_ENSURE(s_nRefCount > 0, "OPropertyArrayUsageHelper::~OPropertyArrayUsageHelper : " + "suspicious call : have a refcount of 0 !"); + if (!--s_nRefCount) + { + delete s_pProps; + s_pProps = nullptr; + } +} + +template <class TYPE>::cppu::IPropertyArrayHelper* OPropertyArrayUsageHelper<TYPE>::getArrayHelper() +{ + OSL_ENSURE( + s_nRefCount, + "OPropertyArrayUsageHelper::getArrayHelper : suspicious call : have a refcount of 0 !"); + if (!s_pProps) + { + ::osl::MutexGuard aGuard(s_aMutex); + if (!s_pProps) + { + s_pProps = createArrayHelper(); + OSL_ENSURE(s_pProps, "OPropertyArrayUsageHelper::getArrayHelper : createArrayHelper " + "returned nonsense !"); + } + } + return s_pProps; +} + +class OBase_Mutex +{ +public: + ::osl::Mutex m_aMutex; +}; + +namespace internal +{ +template <class T> void implCopySequence(const T* _pSource, T*& _pDest, sal_Int32 _nSourceLen) +{ + for (sal_Int32 i = 0; i < _nSourceLen; ++i, ++_pSource, ++_pDest) + *_pDest = *_pSource; +} +} + +/// concat two sequences +template <class T> +css::uno::Sequence<T> concatSequences(const css::uno::Sequence<T>& _rLeft, + const css::uno::Sequence<T>& _rRight) +{ + sal_Int32 nLeft(_rLeft.getLength()), nRight(_rRight.getLength()); + const T* pLeft = _rLeft.getConstArray(); + const T* pRight = _rRight.getConstArray(); + + sal_Int32 nReturnLen(nLeft + nRight); + css::uno::Sequence<T> aReturn(nReturnLen); + T* pReturn = aReturn.getArray(); + + internal::implCopySequence(pLeft, pReturn, nLeft); + internal::implCopySequence(pRight, pReturn, nRight); + + return aReturn; +} +} +} + +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_SUBCOMPONENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_types.cxx b/connectivity/source/drivers/mysqlc/mysqlc_types.cxx new file mode 100644 index 000000000..219e0d553 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_types.cxx @@ -0,0 +1,679 @@ +/* -*- 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 <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include "mysqlc_types.hxx" + +using namespace com::sun::star::sdbc; + +TypeInfoDef const mysqlc_types[] = { + + // ------------- MySQL-Type: BIT. SDBC-Type: Bit ------------- + { + "BIT", // Typename + com::sun::star::sdbc::DataType::BIT, // sdbc-type + 1, // Precision + "", // Literal prefix + "", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "BIT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ------------ MySQL-Type: BOOL. SDBC-Type: Bit ------------- + { + "BOOL", // Typename + com::sun::star::sdbc::DataType::BIT, // sdbc-type + 1, // Precision + "", // Literal prefix + "", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "BOOL", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // --------- MySQL-Type: TINYINT SDBC-Type: TINYINT ---------- + { + "TINYINT", // Typename + com::sun::star::sdbc::DataType::TINYINT, // sdbc-type + 3, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "TINYINT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: BIGINT SDBC-Type: BIGINT ---------- + { + "BIGINT", // Typename + com::sun::star::sdbc::DataType::BIGINT, // sdbc-type + 19, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "BIGINT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: LONG VARBINARY SDBC-Type: LONGVARBINARY ---------- + { + "LONG VARBINARY", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + 16777215, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "LONG VARBINARY", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: MEDIUMBLOB SDBC-Type: LONGVARBINARY ---------- + { + "MEDIUMBLOB", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + 16777215, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "MEDIUMBLOB", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: LONGBLOB SDBC-Type: LONGVARBINARY ---------- + { + "LONGBLOB", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + -1, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "LONGBLOB", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: BLOB SDBC-Type: LONGVARBINARY ---------- + { + "BLOB", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + 0xFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "BLOB", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TINYBLOB SDBC-Type: LONGVARBINARY ---------- + { + "TINYBLOB", // Typename + com::sun::star::sdbc::DataType::LONGVARBINARY, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TINYBLOB", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: VARBINARY SDBC-Type: VARBINARY ---------- + { + "VARBINARY", // Typename + com::sun::star::sdbc::DataType::VARBINARY, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "(M)", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "VARBINARY", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: BINARY SDBC-Type: BINARY ---------- + { + "BINARY", // Typename + com::sun::star::sdbc::DataType::BINARY, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "(M)", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + true, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "VARBINARY", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: LONG VARCHAR SDBC-Type: LONG VARCHAR ---------- + { + "LONG VARCHAR", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFFFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "LONG VARCHAR", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: MEDIUMTEXT SDBC-Type: LONG VARCHAR ---------- + { + "MEDIUMTEXT", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFFFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "MEDIUMTEXT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: LONGTEXT SDBC-Type: LONG VARCHAR ---------- + { + "LONGTEXT", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFFFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "LONGTEXT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TEXT SDBC-Type: LONG VARCHAR ---------- + { + "TEXT", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TEXT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TINYTEXT SDBC-Type: LONG VARCHAR ---------- + { + "TINYTEXT", // Typename + com::sun::star::sdbc::DataType::LONGVARCHAR, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TINYTEXT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: CHAR SDBC-Type: CHAR ---------- + { + "CHAR", // Typename + com::sun::star::sdbc::DataType::CHAR, // sdbc-type + 0xFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "(M)", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "NUMERIC", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: DECIMAL SDBC-Type: DECIMAL ---------- + { + "DECIMAL", // Typename + com::sun::star::sdbc::DataType::DECIMAL, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M[,D])] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "DECIMAL", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: NUMERIC SDBC-Type: NUMERIC ---------- + { + "NUMERIC", // Typename + com::sun::star::sdbc::DataType::NUMERIC, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M[,D])] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "NUMERIC", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: INTEGER SDBC-Type: INTEGER ---------- + { + "INTEGER", // Typename + com::sun::star::sdbc::DataType::INTEGER, // sdbc-type + 10, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "INTEGER", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: INT SDBC-Type: INTEGER ---------- + { + "INT", // Typename + com::sun::star::sdbc::DataType::INTEGER, // sdbc-type + 10, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "INT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: MEDIUMINT SDBC-Type: INTEGER ---------- + { + "MEDIUMINT", // Typename + com::sun::star::sdbc::DataType::INTEGER, // sdbc-type + 7, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "MEDIUMINT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: SMALLINT SDBC-Type: INTEGER ---------- + { + "SMALLINT", // Typename + com::sun::star::sdbc::DataType::SMALLINT, // sdbc-type + 5, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M)] [UNSIGNED] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + true, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "SMALLINT", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: FLOAT SDBC-Type: REAL ---------- + { + "FLOAT", // Typename + com::sun::star::sdbc::DataType::REAL, // sdbc-type + 10, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M,D)] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "FLOAT", // local type name + -38, // minimum scale + 38 // maximum scale + }, + + // ----------- MySQL-Type: DOUBLE SDBC-Type: DOUBLE ---------- + { + "DOUBLE", // Typename + com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M,D)] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "DOUBLE", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: DOUBLE PRECISION SDBC-Type: DOUBLE ---------- + { + "DOUBLE PRECISION", // Typename + com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M,D)] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "DOUBLE PRECISION", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: REAL SDBC-Type: DOUBLE ---------- + { + "REAL", // Typename + com::sun::star::sdbc::DataType::DOUBLE, // sdbc-type + 17, // Precision + "", // Literal prefix + "", // Literal suffix + "[(M,D)] [ZEROFILL]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + true, // auto_increment + "REAL", // local type name + -308, // minimum scale + 308 // maximum scale + }, + + // ----------- MySQL-Type: VARCHAR SDBC-Type: VARCHAR ---------- + { + "VARCHAR", // Typename + com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type + 255, // Precision + "'", // Literal prefix + "'", // Literal suffix + "(M)", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "VARCHAR", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: ENUM SDBC-Type: VARCHAR ---------- + { + "ENUM", // Typename + com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type + 0xFFFF, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "ENUM", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: SET SDBC-Type: VARCHAR ---------- + { + "SET", // Typename + com::sun::star::sdbc::DataType::VARCHAR, // sdbc-type + 64, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "SET", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: DATE SDBC-Type: DATE ---------- + { + "DATE", // Typename + com::sun::star::sdbc::DataType::DATE, // sdbc-type + 0, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "DATE", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TIME SDBC-Type: TIME ---------- + { + "TIME", // Typename + com::sun::star::sdbc::DataType::TIME, // sdbc-type + 0, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TIME", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: DATETIME SDBC-Type: TIMESTAMP ---------- + { + "DATETIME", // Typename + com::sun::star::sdbc::DataType::TIMESTAMP, // sdbc-type + 0, // Precision + "'", // Literal prefix + "'", // Literal suffix + "", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "DATETIME", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TIMESTAMP SDBC-Type: TIMESTAMP ---------- + { + "TIMESTAMP", // Typename + com::sun::star::sdbc::DataType::TIMESTAMP, // sdbc-type + 0, // Precision + "'", // Literal prefix + "'", // Literal suffix + "[(M)]", // Create params + com::sun::star::sdbc::ColumnValue::NULLABLE, // nullable + false, // case sensitive + com::sun::star::sdbc::ColumnSearch::FULL, // searchable + false, // unsignable + false, // fixed_prec_scale + false, // auto_increment + "TIMESTAMP", // local type name + 0, // minimum scale + 0 // maximum scale + }, + + // ----------- MySQL-Type: TIMESTAMP SDBC-Type: TIMESTAMP ---------- + { nullptr, 0, 0, nullptr, nullptr, nullptr, 0, false, 0, false, false, false, nullptr, 0, 0 } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_types.hxx b/connectivity/source/drivers/mysqlc/mysqlc_types.hxx new file mode 100644 index 000000000..5f577ee03 --- /dev/null +++ b/connectivity/source/drivers/mysqlc/mysqlc_types.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_MYSQLC_SOURCE_MYSQLC_TYPES_HXX +#define INCLUDED_MYSQLC_SOURCE_MYSQLC_TYPES_HXX + +#include <sal/types.h> + +struct TypeInfoDef +{ + const char* typeName; + sal_Int32 dataType; + sal_Int32 precision; + const char* literalPrefix; + const char* literalSuffix; + const char* createParams; + sal_Int16 nullable; + bool caseSensitive; + sal_Int16 searchable; + bool isUnsigned; + bool fixedPrecScale; + bool autoIncrement; + const char* localTypeName; + sal_Int32 minScale; + sal_Int32 maxScale; +}; + +extern TypeInfoDef const mysqlc_types[]; + +#endif // INCLUDED_MYSQLC_SOURCE_MYSQLC_TYPES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/OConnection.cxx b/connectivity/source/drivers/odbc/OConnection.cxx new file mode 100644 index 000000000..26a549814 --- /dev/null +++ b/connectivity/source/drivers/odbc/OConnection.cxx @@ -0,0 +1,547 @@ +/* -*- 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 <odbc/OTools.hxx> +#include <odbc/OConnection.hxx> +#include <odbc/ODatabaseMetaData.hxx> +#include <odbc/OFunctions.hxx> +#include <odbc/ODriver.hxx> +#include <odbc/OStatement.hxx> +#include <odbc/OPreparedStatement.hxx> +#include <connectivity/dbcharset.hxx> +#include <connectivity/dbexception.hxx> + +#include <sal/log.hxx> + +#include <string.h> + +using namespace connectivity::odbc; +using namespace connectivity; +using namespace dbtools; + + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +OConnection::OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver) + :m_xDriver(_pDriver) + ,m_aConnectionHandle(nullptr) + ,m_pDriverHandleCopy(_pDriverHandle) + ,m_nStatementCount(0) + ,m_bClosed(false) + ,m_bUseCatalog(false) + ,m_bUseOldDateFormat(false) + ,m_bIgnoreDriverPrivileges(false) + ,m_bPreventGetVersionColumns(false) + ,m_bReadOnly(true) +{ +} + +OConnection::~OConnection() +{ + if(!isClosed( )) + close(); + + if ( SQL_NULL_HANDLE != m_aConnectionHandle ) + { + SQLRETURN rc; + + if (!m_bClosed) + { + rc = N3SQLDisconnect( m_aConnectionHandle ); + OSL_ENSURE( rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO, "Failure from SQLDisconnect" ); + } + + rc = N3SQLFreeHandle( SQL_HANDLE_DBC, m_aConnectionHandle ); + OSL_ENSURE( rc == SQL_SUCCESS , "Failure from SQLFreeHandle for connection"); + + m_aConnectionHandle = SQL_NULL_HANDLE; + } +} + +oslGenericFunction OConnection::getOdbcFunction(ODBC3SQLFunctionId _nIndex) const +{ + OSL_ENSURE(m_xDriver, "OConnection::getOdbcFunction: m_xDriver is null!"); + return m_xDriver->getOdbcFunction(_nIndex); +} + +SQLRETURN OConnection::OpenConnection(const OUString& aConnectStr, sal_Int32 nTimeOut, bool bSilent) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + if (m_aConnectionHandle == SQL_NULL_HANDLE) + return -1; + + SQLRETURN nSQLRETURN = 0; + SDB_ODBC_CHAR szConnStrOut[4096] = {}; + SDB_ODBC_CHAR szConnStrIn[2048] = {}; + SQLSMALLINT cbConnStrOut; + OString aConStr(OUStringToOString(aConnectStr,getTextEncoding())); + memcpy(szConnStrIn, aConStr.getStr(), std::min<sal_Int32>(sal_Int32(2048),aConStr.getLength())); + +#ifndef MACOSX + N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_LOGIN_TIMEOUT,reinterpret_cast<SQLPOINTER>(nTimeOut),SQL_IS_UINTEGER); +#else + (void)nTimeOut; /* WaE */ +#endif + +#ifdef LINUX + (void) bSilent; + nSQLRETURN = N3SQLDriverConnect(m_aConnectionHandle, + nullptr, + szConnStrIn, + static_cast<SQLSMALLINT>(std::min(sal_Int32(2048),aConStr.getLength())), + szConnStrOut, + SQLSMALLINT(sizeof(szConnStrOut)/sizeof(SDB_ODBC_CHAR)) -1, + &cbConnStrOut, + SQL_DRIVER_NOPROMPT); + if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA || SQL_SUCCESS_WITH_INFO == nSQLRETURN) + return nSQLRETURN; +#else + + SQLUSMALLINT nSilent = bSilent ? SQL_DRIVER_NOPROMPT : SQL_DRIVER_COMPLETE; + nSQLRETURN = N3SQLDriverConnect(m_aConnectionHandle, + nullptr, + szConnStrIn, + static_cast<SQLSMALLINT>(std::min<sal_Int32>(sal_Int32(2048),aConStr.getLength())), + szConnStrOut, + SQLSMALLINT(sizeof szConnStrOut), + &cbConnStrOut, + nSilent); + if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA) + return nSQLRETURN; + + m_bClosed = false; + +#endif //LINUX + + try + { + OUString aVal; + OTools::GetInfo(this,m_aConnectionHandle,SQL_DATA_SOURCE_READ_ONLY,aVal,*this,getTextEncoding()); + m_bReadOnly = aVal == "Y"; + } + catch(Exception&) + { + m_bReadOnly = true; + } + try + { + OUString sVersion; + OTools::GetInfo(this,m_aConnectionHandle,SQL_DRIVER_ODBC_VER,sVersion,*this,getTextEncoding()); + m_bUseOldDateFormat = sVersion == "02.50" || sVersion == "02.00"; + } + catch(Exception&) + { + } + + + // autocommit is always default + + if (!m_bReadOnly) + N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(SQL_AUTOCOMMIT_ON),SQL_IS_INTEGER); + + return nSQLRETURN; +} + +SQLRETURN OConnection::Construct(const OUString& url,const Sequence< PropertyValue >& info) +{ + m_aConnectionHandle = SQL_NULL_HANDLE; + m_sURL = url; + setConnectionInfo(info); + + N3SQLAllocHandle(SQL_HANDLE_DBC,m_pDriverHandleCopy,&m_aConnectionHandle); + if(m_aConnectionHandle == SQL_NULL_HANDLE) + throw SQLException(); + + sal_Int32 nLen = url.indexOf(':'); + nLen = url.indexOf(':',nLen+2); + OUString aDSN("DSN="), aUID, aPWD, aSysDrvSettings; + aDSN += url.copy(nLen+1); + + sal_Int32 nTimeout = 20; + bool bSilent = true; + const PropertyValue *pBegin = info.getConstArray(); + const PropertyValue *pEnd = pBegin + info.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if( pBegin->Name == "Timeout") + { + if( ! (pBegin->Value >>= nTimeout) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property Timeout"); + } + else if( pBegin->Name == "Silent") + { + if( ! (pBegin->Value >>= bSilent) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property Silent"); + } + else if( pBegin->Name == "IgnoreDriverPrivileges") + { + if( ! (pBegin->Value >>= m_bIgnoreDriverPrivileges) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property IgnoreDriverPrivileges"); + } + else if( pBegin->Name == "PreventGetVersionColumns") + { + if( ! (pBegin->Value >>= m_bPreventGetVersionColumns) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property PreventGetVersionColumns"); + } + else if( pBegin->Name == "IsAutoRetrievingEnabled") + { + bool bAutoRetrievingEnabled = false; + if( ! (pBegin->Value >>= bAutoRetrievingEnabled) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property IsAutoRetrievingEnabled"); + enableAutoRetrievingEnabled(bAutoRetrievingEnabled); + } + else if( pBegin->Name == "AutoRetrievingStatement") + { + OUString sGeneratedValueStatement; + if( ! (pBegin->Value >>= sGeneratedValueStatement) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property AutoRetrievingStatement"); + setAutoRetrievingStatement(sGeneratedValueStatement); + } + else if( pBegin->Name == "user") + { + if( ! (pBegin->Value >>= aUID) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property user"); + aDSN += ";UID=" + aUID; + } + else if( pBegin->Name == "password") + { + if( ! (pBegin->Value >>= aPWD) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property password"); + aDSN += ";PWD=" + aPWD; + } + else if( pBegin->Name == "UseCatalog") + { + if( !( pBegin->Value >>= m_bUseCatalog) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property UseCatalog"); + } + else if( pBegin->Name == "SystemDriverSettings") + { + if( ! (pBegin->Value >>= aSysDrvSettings) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property SystemDriverSettings"); + aDSN += ";" + aSysDrvSettings; + } + else if( pBegin->Name == "CharSet") + { + OUString sIanaName; + if( ! (pBegin->Value >>= sIanaName) ) + SAL_WARN("connectivity.odbc", "Construct: unable to get property CharSet"); + + ::dbtools::OCharsetMap aLookupIanaName; + ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName); + if (aLookup != aLookupIanaName.end()) + m_nTextEncoding = (*aLookup).getEncoding(); + else + m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW; + if(m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW) + m_nTextEncoding = osl_getThreadTextEncoding(); + } + } + m_sUser = aUID; + + SQLRETURN nSQLRETURN = OpenConnection(aDSN,nTimeout, bSilent); + if (nSQLRETURN == SQL_ERROR || nSQLRETURN == SQL_NO_DATA) + { + OTools::ThrowException(this,nSQLRETURN,m_aConnectionHandle,SQL_HANDLE_DBC,*this,false); + } + return nSQLRETURN; +} +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.odbc.OConnection", "com.sun.star.sdbc.Connection") + + +Reference< XStatement > SAL_CALL OConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference< XStatement > xReturn = new OStatement(this); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference< XPreparedStatement > xReturn = new OPreparedStatement(this,sql); + m_aStatements.push_back(WeakReferenceHelper(xReturn)); + return xReturn; +} + +Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this ); + return nullptr; +} + +OUString SAL_CALL OConnection::nativeSQL( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + OString aSql(OUStringToOString(sql,getTextEncoding())); + char pOut[2048]; + SQLINTEGER nOutLen; + OTools::ThrowException(this,N3SQLNativeSql(m_aConnectionHandle,reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())),aSql.getLength(),reinterpret_cast<SDB_ODBC_CHAR*>(pOut),sizeof pOut - 1,&nOutLen),m_aConnectionHandle,SQL_HANDLE_DBC,*this); + return OUString(pOut,nOutLen,getTextEncoding()); +} + +void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OTools::ThrowException(this,N3SQLSetConnectAttr(m_aConnectionHandle, + SQL_ATTR_AUTOCOMMIT, + reinterpret_cast<SQLPOINTER>((autoCommit) ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF) ,SQL_IS_INTEGER), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); +} + +sal_Bool SAL_CALL OConnection::getAutoCommit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + sal_uInt32 nOption = 0; + OTools::ThrowException(this,N3SQLGetConnectAttr(m_aConnectionHandle, + SQL_ATTR_AUTOCOMMIT, &nOption,0,nullptr),m_aConnectionHandle,SQL_HANDLE_DBC,*this); + return nOption == SQL_AUTOCOMMIT_ON ; +} + +void SAL_CALL OConnection::commit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OTools::ThrowException(this,N3SQLEndTran(SQL_HANDLE_DBC,m_aConnectionHandle,SQL_COMMIT),m_aConnectionHandle,SQL_HANDLE_DBC,*this); +} + +void SAL_CALL OConnection::rollback( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OTools::ThrowException(this,N3SQLEndTran(SQL_HANDLE_DBC,m_aConnectionHandle,SQL_ROLLBACK),m_aConnectionHandle,SQL_HANDLE_DBC,*this); +} + +sal_Bool SAL_CALL OConnection::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + return OConnection_BASE::rBHelper.bDisposed; +} + +Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new ODatabaseMetaData(m_aConnectionHandle,this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OTools::ThrowException(this, + N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_ACCESS_MODE,reinterpret_cast< SQLPOINTER >( readOnly ),SQL_IS_INTEGER), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); +} + +sal_Bool SAL_CALL OConnection::isReadOnly() +{ + // const member which will initialized only once + return m_bReadOnly; +} + +void SAL_CALL OConnection::setCatalog( const OUString& catalog ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OString aCat(OUStringToOString(catalog,getTextEncoding())); + OTools::ThrowException(this, + N3SQLSetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,const_cast<char *>(aCat.getStr()),SQL_NTS), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); +} + +OUString SAL_CALL OConnection::getCatalog( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + SQLINTEGER nValueLen; + char pCat[1024]; + OTools::ThrowException(this, + N3SQLGetConnectAttr(m_aConnectionHandle,SQL_ATTR_CURRENT_CATALOG,pCat,(sizeof pCat)-1,&nValueLen), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); + + return OUString(pCat,nValueLen,getTextEncoding()); +} + +void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 level ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + OTools::ThrowException(this,N3SQLSetConnectAttr(m_aConnectionHandle, + SQL_ATTR_TXN_ISOLATION, + reinterpret_cast<SQLPOINTER>(level),SQL_IS_INTEGER), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); +} + +sal_Int32 SAL_CALL OConnection::getTransactionIsolation( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + sal_Int32 nTxn = 0; + SQLINTEGER nValueLen; + OTools::ThrowException(this, + N3SQLGetConnectAttr(m_aConnectionHandle,SQL_ATTR_TXN_ISOLATION,&nTxn,sizeof nTxn,&nValueLen), + m_aConnectionHandle,SQL_HANDLE_DBC,*this); + return nTxn; +} + +Reference< css::container::XNameAccess > SAL_CALL OConnection::getTypeMap( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + + return nullptr; +} + +void SAL_CALL OConnection::setTypeMap( const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::setTypeMap", *this ); +} + +// XCloseable +void SAL_CALL OConnection::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + } + dispose(); +} + +// XWarningsSupplier +Any SAL_CALL OConnection::getWarnings( ) +{ + return Any(); +} + +void SAL_CALL OConnection::clearWarnings( ) +{ +} + +void OConnection::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + OConnection_BASE::disposing(); + + for (auto const& connection : m_aConnections) + connection.second->dispose(); + + m_aConnections.clear(); + + if(!m_bClosed) + N3SQLDisconnect(m_aConnectionHandle); + m_bClosed = true; +} + +SQLHANDLE OConnection::createStatementHandle() +{ + rtl::Reference<OConnection> xConnectionTemp = this; + bool bNew = false; + try + { + sal_Int32 nMaxStatements = getMetaData()->getMaxStatements(); + if(nMaxStatements && nMaxStatements <= m_nStatementCount) + { + rtl::Reference xConnection(new OConnection(m_pDriverHandleCopy,m_xDriver.get())); + xConnection->Construct(m_sURL,getConnectionInfo()); + xConnectionTemp = xConnection; + bNew = true; + } + } + catch(SQLException&) + { + } + + SQLHANDLE aStatementHandle = SQL_NULL_HANDLE; + N3SQLAllocHandle(SQL_HANDLE_STMT,xConnectionTemp->getConnection(),&aStatementHandle); + ++m_nStatementCount; + if(bNew) + m_aConnections.emplace(aStatementHandle,xConnectionTemp); + + return aStatementHandle; + +} + +void OConnection::freeStatementHandle(SQLHANDLE& _pHandle) +{ + if( SQL_NULL_HANDLE == _pHandle ) + return; + + auto aFind = m_aConnections.find(_pHandle); + + N3SQLFreeStmt(_pHandle,SQL_RESET_PARAMS); + N3SQLFreeStmt(_pHandle,SQL_UNBIND); + N3SQLFreeStmt(_pHandle,SQL_CLOSE); + N3SQLFreeHandle(SQL_HANDLE_STMT,_pHandle); + + _pHandle = SQL_NULL_HANDLE; + + if(aFind != m_aConnections.end()) + { + aFind->second->dispose(); + m_aConnections.erase(aFind); + } + --m_nStatementCount; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/ODatabaseMetaData.cxx b/connectivity/source/drivers/odbc/ODatabaseMetaData.cxx new file mode 100644 index 000000000..c9ed165a8 --- /dev/null +++ b/connectivity/source/drivers/odbc/ODatabaseMetaData.cxx @@ -0,0 +1,1717 @@ +/* -*- 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 <odbc/ODatabaseMetaData.hxx> +#include <odbc/OTools.hxx> +#include <odbc/ODatabaseMetaDataResultSet.hxx> +#include <FDatabaseMetaDataResultSet.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <TPrivilegesResultSet.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +using namespace connectivity::odbc; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +ODatabaseMetaData::ODatabaseMetaData(const SQLHANDLE _pHandle,OConnection* _pCon) + : ::connectivity::ODatabaseMetaDataBase(_pCon,_pCon->getConnectionInfo()) + ,m_aConnectionHandle(_pHandle) + ,m_pConnection(_pCon) + ,m_bUseCatalog(true) +{ + OSL_ENSURE(m_pConnection,"ODatabaseMetaData::ODatabaseMetaData: No connection set!"); + if(!m_pConnection->isCatalogUsed()) + { + osl_atomic_increment( &m_refCount ); + try + { + m_bUseCatalog = !(usesLocalFiles() || usesLocalFilePerTable()); + } + catch(SQLException& ) + { // doesn't matter here + } + osl_atomic_decrement( &m_refCount ); + } +} + +ODatabaseMetaData::~ODatabaseMetaData() +{ +} + +Reference< XResultSet > ODatabaseMetaData::impl_getTypeInfo_throw( ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openTypeInfo(); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo); + } + + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCatalogs( ) +{ + Reference< XResultSet > xRef; + if(!m_bUseCatalog) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eCatalogs); + } + else + { + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openCatalogs(); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eCatalogs); + } + } + + return xRef; +} + +OUString ODatabaseMetaData::impl_getCatalogSeparator_throw( ) +{ + OUString aVal; + if ( m_bUseCatalog ) + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_NAME_SEPARATOR,aVal,*this,m_pConnection->getTextEncoding()); + + return aVal; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getSchemas( ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openSchemas(); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eSchemas); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumnPrivileges( + const Any& catalog, const OUString& schema, const OUString& table, + const OUString& columnNamePattern ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openColumnPrivileges(m_bUseCatalog ? catalog : Any(),schema,table,columnNamePattern); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumnPrivileges); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns( + const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openColumns(m_bUseCatalog ? catalog : Any(),schemaPattern,tableNamePattern,columnNamePattern); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables( + const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, const Sequence< OUString >& types ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openTables(m_bUseCatalog ? catalog : Any(),schemaPattern,tableNamePattern,types); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTables); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedureColumns( + const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern, const OUString& columnNamePattern ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openProcedureColumns(m_bUseCatalog ? catalog : Any(),schemaPattern,procedureNamePattern,columnNamePattern); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eProcedureColumns); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getProcedures( + const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openProcedures(m_bUseCatalog ? catalog : Any(),schemaPattern,procedureNamePattern); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eProcedures); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getVersionColumns( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + Reference< XResultSet > xRef; + bool bSuccess = false; + try + { + if ( !m_pConnection->preventGetVersionColumns() ) + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openVersionColumns(m_bUseCatalog ? catalog : Any(),schema,table); + bSuccess = true; + } + } + catch(SQLException&) + { + } + + if ( !bSuccess ) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eVersionColumns); + } + + return xRef; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_BINARY_LITERAL_LEN,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_ROW_SIZE,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_CATALOG_NAME_LEN,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_CHAR_LITERAL_LEN,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMN_NAME_LEN,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_INDEX,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_CURSOR_NAME_LEN,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_DRIVER_CONNECTIONS/*SQL_ACTIVE_CONNECTIONS*/,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_TABLE,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_STATEMENT_LEN,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_TABLE_NAME_LEN,nValue,*this); + return nValue; +} + +sal_Int32 ODatabaseMetaData::impl_getMaxTablesInSelect_throw( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_TABLES_IN_SELECT,nValue,*this); + return nValue; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getExportedKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openExportedKeys(m_bUseCatalog ? catalog : Any(),schema,table); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eExportedKeys); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getImportedKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openImportedKeys(m_bUseCatalog ? catalog : Any(),schema,table); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eImportedKeys); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPrimaryKeys( + const Any& catalog, const OUString& schema, const OUString& table ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openPrimaryKeys(m_bUseCatalog ? catalog : Any(),schema,table); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::ePrimaryKeys); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo( + const Any& catalog, const OUString& schema, const OUString& table, + sal_Bool unique, sal_Bool approximate ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openIndexInfo(m_bUseCatalog ? catalog : Any(),schema,table,unique,approximate); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eIndexInfo); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getBestRowIdentifier( + const Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, + sal_Bool nullable ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openBestRowIdentifier(m_bUseCatalog ? catalog : Any(),schema,table,scope,nullable); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eBestRowIdentifier); + } + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges( + const Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) +{ + if ( m_pConnection->isIgnoreDriverPrivilegesEnabled() ) + { + return new OResultSetPrivileges(this,catalog,schemaPattern,tableNamePattern); + } + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + Reference< XResultSet > xRef = pResult; + pResult->openTablePrivileges(m_bUseCatalog ? catalog : Any(),schemaPattern,tableNamePattern); + return xRef; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getCrossReference( + const Any& primaryCatalog, const OUString& primarySchema, + const OUString& primaryTable, const Any& foreignCatalog, + const OUString& foreignSchema, const OUString& foreignTable ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openForeignKeys(m_bUseCatalog ? primaryCatalog : Any(),primarySchema.toChar() == '%' ? &primarySchema : nullptr,&primaryTable, + m_bUseCatalog ? foreignCatalog : Any(), foreignSchema.toChar() == '%' ? &foreignSchema : nullptr,&foreignTable); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eCrossReference); + } + return xRef; +} + +sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + OUString aVal; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_ROW_SIZE_INCLUDES_LONG,aVal,*this,m_pConnection->getTextEncoding()); + return aVal.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_QUOTED_IDENTIFIER_CASE,nValue,*this); + return nValue == SQL_IC_LOWER; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_CASE,nValue,*this); + return nValue == SQL_IC_LOWER; +} + +bool ODatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_QUOTED_IDENTIFIER_CASE,nValue,*this); + return nValue == SQL_IC_MIXED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_CASE,nValue,*this); + return nValue == SQL_IC_MIXED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_QUOTED_IDENTIFIER_CASE,nValue,*this); + return nValue == SQL_IC_UPPER; +} + +sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_CASE,nValue,*this); + return nValue == SQL_IC_UPPER; +} + +bool ODatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ALTER_TABLE,nValue,*this); + return (nValue & SQL_AT_ADD_COLUMN) == SQL_AT_ADD_COLUMN; +} + +bool ODatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ALTER_TABLE,nValue,*this); + return ((nValue & SQL_AT_DROP_COLUMN) == SQL_AT_DROP_COLUMN) || + ((nValue & SQL_AT_DROP_COLUMN_CASCADE) == SQL_AT_DROP_COLUMN_CASCADE) || + ((nValue & SQL_AT_DROP_COLUMN_RESTRICT) == SQL_AT_DROP_COLUMN_RESTRICT); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_INDEX_SIZE,nValue,*this); + return nValue; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NON_NULLABLE_COLUMNS,nValue,*this); + return nValue == SQL_NNC_NON_NULL; +} + +OUString SAL_CALL ODatabaseMetaData::getCatalogTerm( ) +{ + OUString aVal; + if(m_bUseCatalog) + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_TERM,aVal,*this,m_pConnection->getTextEncoding()); + return aVal; +} + +OUString ODatabaseMetaData::impl_getIdentifierQuoteString_throw( ) +{ + OUString aVal; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_QUOTE_CHAR,aVal,*this,m_pConnection->getTextEncoding()); + return aVal; +} + +OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( ) +{ + OUString aVal; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SPECIAL_CHARACTERS,aVal,*this,m_pConnection->getTextEncoding()); + return aVal; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + return nValue != SQL_CN_NONE; +} + +bool ODatabaseMetaData::impl_isCatalogAtStart_throw( ) +{ + SQLUSMALLINT nValue=0; + if ( m_bUseCatalog ) + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_LOCATION,nValue,*this); + return nValue == SQL_CL_START; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this); + return nValue == SQL_TC_DDL_IGNORE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this); + return nValue == SQL_TC_DDL_COMMIT; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this); + return nValue == SQL_TC_DML; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this); + return nValue == SQL_TC_ALL; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nValue,*this); + return (nValue & SQL_CA1_POS_DELETE) == SQL_CA1_POS_DELETE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nValue,*this); + return (nValue & SQL_CA1_POS_UPDATE) == SQL_CA1_POS_UPDATE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_ROLLBACK_BEHAVIOR,nValue,*this); + return nValue == SQL_CB_PRESERVE || nValue == SQL_CB_CLOSE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_COMMIT_BEHAVIOR,nValue,*this); + return nValue == SQL_CB_PRESERVE || nValue == SQL_CB_CLOSE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_COMMIT_BEHAVIOR,nValue,*this); + return nValue == SQL_CB_PRESERVE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_ROLLBACK_BEHAVIOR,nValue,*this); + return nValue == SQL_CB_PRESERVE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_ISOLATION_OPTION,nValue,*this); + return (nValue & static_cast<SQLUINTEGER>(level)) == static_cast<SQLUINTEGER>(level); +} + +bool ODatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this); + return (nValue & SQL_SU_DML_STATEMENTS) == SQL_SU_DML_STATEMENTS; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SQL_CONFORMANCE,nValue,*this); + return static_cast<bool>(nValue & SQL_SC_SQL92_FULL); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SQL_CONFORMANCE,nValue,*this); + return static_cast<bool>(nValue &SQL_SC_SQL92_ENTRY); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + OUString aStr; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_INTEGRITY,aStr,*this,m_pConnection->getTextEncoding()); + return aStr.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this); + return (nValue & SQL_SU_INDEX_DEFINITION) == SQL_SU_INDEX_DEFINITION; +} + +bool ODatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this); + return (nValue & SQL_SU_TABLE_DEFINITION) == SQL_SU_TABLE_DEFINITION; +} + +bool ODatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( ) +{ + SQLUINTEGER nValue=0; + if(m_bUseCatalog) + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this); + return (nValue & SQL_CU_TABLE_DEFINITION) == SQL_CU_TABLE_DEFINITION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + SQLUINTEGER nValue=0; + if(m_bUseCatalog) + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this); + return (nValue & SQL_CU_INDEX_DEFINITION) == SQL_CU_INDEX_DEFINITION; +} + +bool ODatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( ) +{ + SQLUINTEGER nValue=0; + if(m_bUseCatalog) + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this); + return (nValue & SQL_CU_DML_STATEMENTS) == SQL_CU_DML_STATEMENTS; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_OJ_CAPABILITIES,nValue,*this); + return ((nValue & (SQL_OJ_FULL|SQL_OJ_LEFT|SQL_OJ_RIGHT|SQL_OJ_NESTED|SQL_OJ_NOT_ORDERED|SQL_OJ_ALL_COMPARISON_OPS|SQL_OJ_INNER)) != 0); +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( ) +{ + Reference< XResultSet > xRef; + try + { + ODatabaseMetaDataResultSet* pResult = new ODatabaseMetaDataResultSet(m_pConnection); + xRef = pResult; + pResult->openTablesTypes(); + } + catch(SQLException&) + { + xRef = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTableTypes); + } + return xRef; +} + +sal_Int32 ODatabaseMetaData::impl_getMaxStatements_throw( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_CONCURRENT_ACTIVITIES,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_PROCEDURE_NAME_LEN,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_SCHEMA_NAME_LEN,nValue,*this); + return nValue; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TXN_CAPABLE,nValue,*this); + return nValue != SQL_TC_NONE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ACCESSIBLE_PROCEDURES,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_PROCEDURES,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nValue,*this); + return (nValue & SQL_CA1_POSITIONED_UPDATE) == SQL_CA1_POSITIONED_UPDATE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ACCESSIBLE_TABLES,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( ) +{ + return m_pConnection->isReadOnly(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_FILE_USAGE,nValue,*this); + return nValue == SQL_FILE_CATALOG; +} + +sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_FILE_USAGE,nValue,*this); + return nValue == SQL_FILE_TABLE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_FUNCTIONS,nValue,*this); + return (nValue & SQL_FN_CVT_CONVERT) == SQL_FN_CVT_CONVERT; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONCAT_NULL_BEHAVIOR,nValue,*this); + return nValue == SQL_CB_NULL; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_COLUMN_ALIAS,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + return nValue != SQL_CN_NONE; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert( sal_Int32 fromType, sal_Int32 toType ) +{ + if(fromType == toType) + return true; + + SQLUINTEGER nValue=0; + switch(fromType) + { + case DataType::BIT: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_BIT,nValue,*this); + break; + case DataType::TINYINT: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_TINYINT,nValue,*this); + break; + case DataType::SMALLINT: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_SMALLINT,nValue,*this); + break; + case DataType::INTEGER: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_INTEGER,nValue,*this); + break; + case DataType::BIGINT: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_BIGINT,nValue,*this); + break; + case DataType::FLOAT: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_FLOAT,nValue,*this); + break; + case DataType::REAL: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_REAL,nValue,*this); + break; + case DataType::DOUBLE: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_DOUBLE,nValue,*this); + break; + case DataType::NUMERIC: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_NUMERIC,nValue,*this); + break; + case DataType::DECIMAL: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_DECIMAL,nValue,*this); + break; + case DataType::CHAR: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_CHAR,nValue,*this); + break; + case DataType::VARCHAR: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_VARCHAR,nValue,*this); + break; + case DataType::LONGVARCHAR: + case DataType::CLOB: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_LONGVARCHAR,nValue,*this); + break; + case DataType::DATE: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_DATE,nValue,*this); + break; + case DataType::TIME: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_TIME,nValue,*this); + break; + case DataType::TIMESTAMP: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_TIMESTAMP,nValue,*this); + break; + case DataType::BINARY: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_BINARY,nValue,*this); + break; + case DataType::VARBINARY: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_VARBINARY,nValue,*this); + break; + case DataType::LONGVARBINARY: + case DataType::BLOB: + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CONVERT_LONGVARBINARY,nValue,*this); + break; + case DataType::SQLNULL: + // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + break; + case DataType::OTHER: + // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + break; + case DataType::OBJECT: + // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + break; + case DataType::DISTINCT: + // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + break; + case DataType::STRUCT: + // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + break; + case DataType::ARRAY: + // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + break; + case DataType::REF: + // OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CORRELATION_NAME,nValue,*this); + break; + } + bool bConvert = false; + switch(toType) + { + case DataType::BIT: + bConvert = (nValue & SQL_CVT_BIT) == SQL_CVT_BIT; + break; + case DataType::TINYINT: + bConvert = (nValue & SQL_CVT_TINYINT) == SQL_CVT_TINYINT; + break; + case DataType::SMALLINT: + bConvert = (nValue & SQL_CVT_SMALLINT) == SQL_CVT_SMALLINT; + break; + case DataType::INTEGER: + bConvert = (nValue & SQL_CVT_INTEGER) == SQL_CVT_INTEGER; + break; + case DataType::BIGINT: + bConvert = (nValue & SQL_CVT_BIGINT) == SQL_CVT_BIGINT; + break; + case DataType::FLOAT: + bConvert = (nValue & SQL_CVT_FLOAT) == SQL_CVT_FLOAT; + break; + case DataType::REAL: + bConvert = (nValue & SQL_CVT_REAL) == SQL_CVT_REAL; + break; + case DataType::DOUBLE: + bConvert = (nValue & SQL_CVT_DOUBLE) == SQL_CVT_DOUBLE; + break; + case DataType::NUMERIC: + bConvert = (nValue & SQL_CVT_NUMERIC) == SQL_CVT_NUMERIC; + break; + case DataType::DECIMAL: + bConvert = (nValue & SQL_CVT_DECIMAL) == SQL_CVT_DECIMAL; + break; + case DataType::CHAR: + bConvert = (nValue & SQL_CVT_CHAR) == SQL_CVT_CHAR; + break; + case DataType::VARCHAR: + bConvert = (nValue & SQL_CVT_VARCHAR) == SQL_CVT_VARCHAR; + break; + case DataType::LONGVARCHAR: + case DataType::CLOB: + bConvert = (nValue & SQL_CVT_LONGVARCHAR) == SQL_CVT_LONGVARCHAR; + break; + case DataType::DATE: + bConvert = (nValue & SQL_CVT_DATE) == SQL_CVT_DATE; + break; + case DataType::TIME: + bConvert = (nValue & SQL_CVT_TIME) == SQL_CVT_TIME; + break; + case DataType::TIMESTAMP: + bConvert = (nValue & SQL_CVT_TIMESTAMP) == SQL_CVT_TIMESTAMP; + break; + case DataType::BINARY: + bConvert = (nValue & SQL_CVT_BINARY) == SQL_CVT_BINARY; + break; + case DataType::VARBINARY: + bConvert = (nValue & SQL_CVT_VARBINARY) == SQL_CVT_VARBINARY; + break; + case DataType::LONGVARBINARY: + case DataType::BLOB: + bConvert = (nValue & SQL_CVT_LONGVARBINARY) == SQL_CVT_LONGVARBINARY; + break; + } + + return bConvert; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_EXPRESSIONS_IN_ORDERBY,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_GROUP_BY,nValue,*this); + return nValue != SQL_GB_NOT_SUPPORTED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_GROUP_BY,nValue,*this); + return nValue != SQL_GB_GROUP_BY_CONTAINS_SELECT; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_GROUP_BY,nValue,*this); + return nValue == SQL_GB_NO_RELATION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MULTIPLE_ACTIVE_TXN,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MULT_RESULT_SETS,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_LIKE_ESCAPE_CLAUSE,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'Y'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ORDER_BY_COLUMNS_IN_SELECT,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.toChar() == 'N'; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_UNION,nValue,*this); + return (nValue & SQL_U_UNION) == SQL_U_UNION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_UNION,nValue,*this); + return (nValue & SQL_U_UNION_ALL) == SQL_U_UNION_ALL; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_IDENTIFIER_CASE,nValue,*this); + return nValue == SQL_IC_MIXED; +} + +bool ODatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_QUOTED_IDENTIFIER_CASE,nValue,*this); + return nValue == SQL_IC_MIXED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NULL_COLLATION,nValue,*this); + return nValue == SQL_NC_END; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NULL_COLLATION,nValue,*this); + return nValue == SQL_NC_START; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NULL_COLLATION,nValue,*this); + return nValue == SQL_NC_HIGH; +} + +sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NULL_COLLATION,nValue,*this); + return nValue == SQL_NC_LOW; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this); + return (nValue & SQL_SU_PROCEDURE_INVOCATION) == SQL_SU_PROCEDURE_INVOCATION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_USAGE,nValue,*this); + return (nValue & SQL_SU_PRIVILEGE_DEFINITION) == SQL_SU_PRIVILEGE_DEFINITION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + SQLUINTEGER nValue=0; + if(m_bUseCatalog) + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this); + return (nValue & SQL_CU_PROCEDURE_INVOCATION) == SQL_CU_PROCEDURE_INVOCATION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + SQLUINTEGER nValue=0; + if(m_bUseCatalog) + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CATALOG_USAGE,nValue,*this); + return (nValue & SQL_CU_PRIVILEGE_DEFINITION) == SQL_CU_PRIVILEGE_DEFINITION; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this); + return (nValue & SQL_SQ_CORRELATED_SUBQUERIES) == SQL_SQ_CORRELATED_SUBQUERIES; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this); + return (nValue & SQL_SQ_COMPARISON) == SQL_SQ_COMPARISON; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this); + return (nValue & SQL_SQ_EXISTS) == SQL_SQ_EXISTS; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this); + return (nValue & SQL_SQ_IN) == SQL_SQ_IN; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SUBQUERIES,nValue,*this); + return (nValue & SQL_SQ_QUANTIFIED) == SQL_SQ_QUANTIFIED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SQL_CONFORMANCE,nValue,*this); + return static_cast<bool>(nValue & SQL_SC_SQL92_INTERMEDIATE); +} + +OUString ODatabaseMetaData::getURLImpl() +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DATA_SOURCE_NAME,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getURL( ) +{ + OUString aValue = m_pConnection->getURL(); + if ( aValue.isEmpty() ) + { + aValue = "sdbc:odbc:" + getURLImpl(); + } + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getUserName( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_USER_NAME,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getDriverName( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_NAME,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getDriverVersion() +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_ODBC_VER,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_VER,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DBMS_NAME,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_PROCEDURE_TERM,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getSchemaTerm( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SCHEMA_TERM,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( ) try +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_VER,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.copy(0,aValue.indexOf('.')).toInt32(); +} +catch (const SQLException &) +{ + return 0; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation( ) +{ + SQLUINTEGER nValue; + sal_Int32 nValueTranslated; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DEFAULT_TXN_ISOLATION,nValue,*this); + switch(nValue) + { + case SQL_TXN_READ_UNCOMMITTED: + nValueTranslated = css::sdbc::TransactionIsolation::READ_UNCOMMITTED; + break; + case SQL_TXN_READ_COMMITTED: + nValueTranslated = css::sdbc::TransactionIsolation::READ_COMMITTED; + break; + case SQL_TXN_REPEATABLE_READ: + nValueTranslated = css::sdbc::TransactionIsolation::REPEATABLE_READ; + break; + case SQL_TXN_SERIALIZABLE: + nValueTranslated = css::sdbc::TransactionIsolation::SERIALIZABLE; + break; + default: + nValueTranslated = 0; + } + return nValueTranslated; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( ) try +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_DRIVER_VER,aValue,*this,m_pConnection->getTextEncoding()); + return aValue.copy(0,aValue.lastIndexOf('.')).toInt32(); +} +catch (const SQLException &) +{ + return 0; +} + +OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_KEYWORDS,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( ) +{ + OUString aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SEARCH_PATTERN_ESCAPE,aValue,*this,m_pConnection->getTextEncoding()); + return aValue; +} + +OUString SAL_CALL ODatabaseMetaData::getStringFunctions( ) +{ + SQLUINTEGER nValue; + OUStringBuffer aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_STRING_FUNCTIONS,nValue,*this); + if(nValue & SQL_FN_STR_ASCII) + aValue.append("ASCII,"); + if(nValue & SQL_FN_STR_BIT_LENGTH) + aValue.append("BIT_LENGTH,"); + if(nValue & SQL_FN_STR_CHAR) + aValue.append("CHAR,"); + if(nValue & SQL_FN_STR_CHAR_LENGTH) + aValue.append("CHAR_LENGTH,"); + if(nValue & SQL_FN_STR_CHARACTER_LENGTH) + aValue.append("CHARACTER_LENGTH,"); + if(nValue & SQL_FN_STR_CONCAT) + aValue.append("CONCAT,"); + if(nValue & SQL_FN_STR_DIFFERENCE) + aValue.append("DIFFERENCE,"); + if(nValue & SQL_FN_STR_INSERT) + aValue.append("INSERT,"); + if(nValue & SQL_FN_STR_LCASE) + aValue.append("LCASE,"); + if(nValue & SQL_FN_STR_LEFT) + aValue.append("LEFT,"); + if(nValue & SQL_FN_STR_LENGTH) + aValue.append("LENGTH,"); + if(nValue & SQL_FN_STR_LOCATE) + aValue.append("LOCATE,"); + if(nValue & SQL_FN_STR_LOCATE_2) + aValue.append("LOCATE_2,"); + if(nValue & SQL_FN_STR_LTRIM) + aValue.append("LTRIM,"); + if(nValue & SQL_FN_STR_OCTET_LENGTH) + aValue.append("OCTET_LENGTH,"); + if(nValue & SQL_FN_STR_POSITION) + aValue.append("POSITION,"); + if(nValue & SQL_FN_STR_REPEAT) + aValue.append("REPEAT,"); + if(nValue & SQL_FN_STR_REPLACE) + aValue.append("REPLACE,"); + if(nValue & SQL_FN_STR_RIGHT) + aValue.append("RIGHT,"); + if(nValue & SQL_FN_STR_RTRIM) + aValue.append("RTRIM,"); + if(nValue & SQL_FN_STR_SOUNDEX) + aValue.append("SOUNDEX,"); + if(nValue & SQL_FN_STR_SPACE) + aValue.append("SPACE,"); + if(nValue & SQL_FN_STR_SUBSTRING) + aValue.append("SUBSTRING,"); + if(nValue & SQL_FN_STR_UCASE) + aValue.append("UCASE,"); + + + if ( !aValue.isEmpty() ) + aValue.setLength(aValue.getLength()-1); + + return aValue.makeStringAndClear(); +} + +OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( ) +{ + SQLUINTEGER nValue; + OUStringBuffer aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_TIMEDATE_FUNCTIONS,nValue,*this); + + if(nValue & SQL_FN_TD_CURRENT_DATE) + aValue.append("CURRENT_DATE,"); + if(nValue & SQL_FN_TD_CURRENT_TIME) + aValue.append("CURRENT_TIME,"); + if(nValue & SQL_FN_TD_CURRENT_TIMESTAMP) + aValue.append("CURRENT_TIMESTAMP,"); + if(nValue & SQL_FN_TD_CURDATE) + aValue.append("CURDATE,"); + if(nValue & SQL_FN_TD_CURTIME) + aValue.append("CURTIME,"); + if(nValue & SQL_FN_TD_DAYNAME) + aValue.append("DAYNAME,"); + if(nValue & SQL_FN_TD_DAYOFMONTH) + aValue.append("DAYOFMONTH,"); + if(nValue & SQL_FN_TD_DAYOFWEEK) + aValue.append("DAYOFWEEK,"); + if(nValue & SQL_FN_TD_DAYOFYEAR) + aValue.append("DAYOFYEAR,"); + if(nValue & SQL_FN_TD_EXTRACT) + aValue.append("EXTRACT,"); + if(nValue & SQL_FN_TD_HOUR) + aValue.append("HOUR,"); + if(nValue & SQL_FN_TD_MINUTE) + aValue.append("MINUTE,"); + if(nValue & SQL_FN_TD_MONTH) + aValue.append("MONTH,"); + if(nValue & SQL_FN_TD_MONTHNAME) + aValue.append("MONTHNAME,"); + if(nValue & SQL_FN_TD_NOW) + aValue.append("NOW,"); + if(nValue & SQL_FN_TD_QUARTER) + aValue.append("QUARTER,"); + if(nValue & SQL_FN_TD_SECOND) + aValue.append("SECOND,"); + if(nValue & SQL_FN_TD_TIMESTAMPADD) + aValue.append("TIMESTAMPADD,"); + if(nValue & SQL_FN_TD_TIMESTAMPDIFF) + aValue.append("TIMESTAMPDIFF,"); + if(nValue & SQL_FN_TD_WEEK) + aValue.append("WEEK,"); + if(nValue & SQL_FN_TD_YEAR) + aValue.append("YEAR,"); + + if ( !aValue.isEmpty() ) + aValue.setLength(aValue.getLength()-1); + + return aValue.makeStringAndClear(); +} + +OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( ) +{ + SQLUINTEGER nValue; + OUStringBuffer aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_SYSTEM_FUNCTIONS,nValue,*this); + + if(nValue & SQL_FN_SYS_DBNAME) + aValue.append("DBNAME,"); + if(nValue & SQL_FN_SYS_IFNULL) + aValue.append("IFNULL,"); + if(nValue & SQL_FN_SYS_USERNAME) + aValue.append("USERNAME,"); + + if ( !aValue.isEmpty() ) + aValue.setLength(aValue.getLength()-1); + + return aValue.makeStringAndClear(); +} + +OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( ) +{ + SQLUINTEGER nValue; + OUStringBuffer aValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_NUMERIC_FUNCTIONS,nValue,*this); + + if(nValue & SQL_FN_NUM_ABS) + aValue.append("ABS,"); + if(nValue & SQL_FN_NUM_ACOS) + aValue.append("ACOS,"); + if(nValue & SQL_FN_NUM_ASIN) + aValue.append("ASIN,"); + if(nValue & SQL_FN_NUM_ATAN) + aValue.append("ATAN,"); + if(nValue & SQL_FN_NUM_ATAN2) + aValue.append("ATAN2,"); + if(nValue & SQL_FN_NUM_CEILING) + aValue.append("CEILING,"); + if(nValue & SQL_FN_NUM_COS) + aValue.append("COS,"); + if(nValue & SQL_FN_NUM_COT) + aValue.append("COT,"); + if(nValue & SQL_FN_NUM_DEGREES) + aValue.append("DEGREES,"); + if(nValue & SQL_FN_NUM_EXP) + aValue.append("EXP,"); + if(nValue & SQL_FN_NUM_FLOOR) + aValue.append("FLOOR,"); + if(nValue & SQL_FN_NUM_LOG) + aValue.append("LOGF,"); + if(nValue & SQL_FN_NUM_LOG10) + aValue.append("LOG10,"); + if(nValue & SQL_FN_NUM_MOD) + aValue.append("MOD,"); + if(nValue & SQL_FN_NUM_PI) + aValue.append("PI,"); + if(nValue & SQL_FN_NUM_POWER) + aValue.append("POWER,"); + if(nValue & SQL_FN_NUM_RADIANS) + aValue.append("RADIANS,"); + if(nValue & SQL_FN_NUM_RAND) + aValue.append("RAND,"); + if(nValue & SQL_FN_NUM_ROUND) + aValue.append("ROUND,"); + if(nValue & SQL_FN_NUM_SIGN) + aValue.append("SIGN,"); + if(nValue & SQL_FN_NUM_SIN) + aValue.append("SIN,"); + if(nValue & SQL_FN_NUM_SQRT) + aValue.append("SQRT,"); + if(nValue & SQL_FN_NUM_TAN) + aValue.append("TAN,"); + if(nValue & SQL_FN_NUM_TRUNCATE) + aValue.append("TRUNCATE,"); + + if ( !aValue.isEmpty() ) + aValue.setLength(aValue.getLength()-1); + + return aValue.makeStringAndClear(); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + SQLUINTEGER nValue; + // SQL_ODBC_SQL_CONFORMANCE is deprecated in ODBC 3.x, but there does not seem te be any equivalent. + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ODBC_SQL_CONFORMANCE,nValue,*this); + SAL_WARN_IF(! (nValue == SQL_OSC_MINIMUM || nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED), + "connectivity.odbc", + "SQL_ODBC_SQL_CONFORMANCE is neither MINIMAL nor CORE nor EXTENDED"); + return nValue == SQL_OSC_EXTENDED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar( ) +{ + SQLUINTEGER nValue; + // SQL_ODBC_SQL_CONFORMANCE is deprecated in ODBC 3.x, but there does not seem te be any equivalent. + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ODBC_SQL_CONFORMANCE,nValue,*this); + SAL_WARN_IF(! (nValue == SQL_OSC_MINIMUM || nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED), + "connectivity.odbc", + "SQL_ODBC_SQL_CONFORMANCE is neither MINIMAL nor CORE nor EXTENDED"); + return nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + SQLUINTEGER nValue; + // SQL_ODBC_SQL_CONFORMANCE is deprecated in ODBC 3.x, but there does not seem te be any equivalent. + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_ODBC_SQL_CONFORMANCE,nValue,*this); + SAL_WARN_IF(! (nValue == SQL_OSC_MINIMUM || nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED), + "connectivity.odbc", + "SQL_ODBC_SQL_CONFORMANCE is neither MINIMAL nor CORE nor EXTENDED"); + return nValue == SQL_OSC_MINIMUM || nValue == SQL_OSC_CORE || nValue == SQL_OSC_EXTENDED; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_OJ_CAPABILITIES,nValue,*this); + return (nValue & SQL_OJ_FULL) == SQL_OJ_FULL; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return supportsFullOuterJoins( ); +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_GROUP_BY,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_ORDER_BY,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_COLUMNS_IN_SELECT,nValue,*this); + return nValue; +} + +sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( ) +{ + SQLUSMALLINT nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_MAX_USER_NAME_LEN,nValue,*this); + return nValue; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType( sal_Int32 setType ) +{ + SQLUINTEGER nValue; + OTools::GetInfo(m_pConnection,m_aConnectionHandle,SQL_CURSOR_SENSITIVITY,nValue,*this); + return (nValue & static_cast<SQLUINTEGER>(setType)) == static_cast<SQLUINTEGER>(setType); +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) +{ + SQLUINTEGER nValue; + SQLUSMALLINT nAskFor( SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 ); + switch(setType) + { + default: + case ResultSetType::FORWARD_ONLY: + nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2; + break; + case ResultSetType::SCROLL_INSENSITIVE: + nAskFor = SQL_STATIC_CURSOR_ATTRIBUTES2; + break; + case ResultSetType::SCROLL_SENSITIVE: + nAskFor = SQL_DYNAMIC_CURSOR_ATTRIBUTES2; + break; + } + + OTools::GetInfo(m_pConnection,m_aConnectionHandle,nAskFor,nValue,*this); + bool bRet = false; + switch(concurrency) + { + case ResultSetConcurrency::READ_ONLY: + bRet = (nValue & SQL_CA2_READ_ONLY_CONCURRENCY) == SQL_CA2_READ_ONLY_CONCURRENCY; + break; + case ResultSetConcurrency::UPDATABLE: + bRet = (nValue & SQL_CA2_OPT_VALUES_CONCURRENCY) == SQL_CA2_OPT_VALUES_CONCURRENCY; + break; + } + return bRet; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 setType ) +{ + SQLUINTEGER nValue; + SQLUSMALLINT nAskFor( SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 ); + switch(setType) + { + default: + case ResultSetType::FORWARD_ONLY: + nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2; + break; + case ResultSetType::SCROLL_INSENSITIVE: + nAskFor = SQL_STATIC_CURSOR_ATTRIBUTES2; + break; + case ResultSetType::SCROLL_SENSITIVE: + nAskFor = SQL_DYNAMIC_CURSOR_ATTRIBUTES2; + break; + } + + OTools::GetInfo(m_pConnection,m_aConnectionHandle,nAskFor,nValue,*this); + return (nValue & SQL_CA2_SENSITIVITY_UPDATES) == SQL_CA2_SENSITIVITY_UPDATES; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 setType ) +{ + SQLUINTEGER nValue; + SQLUSMALLINT nAskFor( SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 ); + switch(setType) + { + default: + case ResultSetType::FORWARD_ONLY: + nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2; + break; + case ResultSetType::SCROLL_INSENSITIVE: + nAskFor = SQL_STATIC_CURSOR_ATTRIBUTES2; + break; + case ResultSetType::SCROLL_SENSITIVE: + nAskFor = SQL_DYNAMIC_CURSOR_ATTRIBUTES2; + break; + } + + OTools::GetInfo(m_pConnection,m_aConnectionHandle,nAskFor,nValue,*this); + return (nValue & SQL_CA2_SENSITIVITY_DELETIONS) != SQL_CA2_SENSITIVITY_DELETIONS; +} + +sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 setType ) +{ + SQLUINTEGER nValue; + SQLUSMALLINT nAskFor( SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 ); + switch(setType) + { + default: + case ResultSetType::FORWARD_ONLY: + nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2; + break; + case ResultSetType::SCROLL_INSENSITIVE: + nAskFor = SQL_STATIC_CURSOR_ATTRIBUTES2; + break; + case ResultSetType::SCROLL_SENSITIVE: + nAskFor = SQL_DYNAMIC_CURSOR_ATTRIBUTES2; + break; + } + + OTools::GetInfo(m_pConnection,m_aConnectionHandle,nAskFor,nValue,*this); + return (nValue & SQL_CA2_SENSITIVITY_ADDITIONS) == SQL_CA2_SENSITIVITY_ADDITIONS; +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 setType ) +{ + return ownUpdatesAreVisible(setType); +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 setType ) +{ + return ownDeletesAreVisible(setType); +} + +sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 setType ) +{ + return ownInsertsAreVisible(setType); +} + +sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 /*setType*/ ) +{ + return false; +} + +sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates( ) +{ + return false; +} + +Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ ) +{ + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx b/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx new file mode 100644 index 000000000..7afd4bed5 --- /dev/null +++ b/connectivity/source/drivers/odbc/ODatabaseMetaDataResultSet.cxx @@ -0,0 +1,1309 @@ +/* -*- 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 <odbc/ODatabaseMetaDataResultSet.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <comphelper/property.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/sequence.hxx> +#include <odbc/OResultSetMetaData.hxx> +#include <odbc/OTools.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbexception.hxx> + +using namespace ::comphelper; + + +using namespace connectivity::odbc; +using namespace cppu; + +using namespace ::com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::util; + + +ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet(OConnection* _pConnection) + :ODatabaseMetaDataResultSet_BASE(m_aMutex) + ,OPropertySetHelper(ODatabaseMetaDataResultSet_BASE::rBHelper) + + ,m_aStatementHandle(_pConnection->createStatementHandle()) + ,m_aStatement(nullptr) + ,m_pConnection(_pConnection) + ,m_nTextEncoding(_pConnection->getTextEncoding()) + ,m_nRowPos(-1) + ,m_nDriverColumnCount(0) + ,m_nCurrentFetchState(0) + ,m_bWasNull(true) + ,m_bEOF(false) +{ + OSL_ENSURE(m_pConnection.is(),"ODatabaseMetaDataResultSet::ODatabaseMetaDataResultSet: No parent set!"); + if( SQL_NULL_HANDLE == m_aStatementHandle ) + throw RuntimeException(); + + osl_atomic_increment( &m_refCount ); + m_pRowStatusArray.reset( new SQLUSMALLINT[1] ); // the default value + osl_atomic_decrement( &m_refCount ); +} + + +ODatabaseMetaDataResultSet::~ODatabaseMetaDataResultSet() +{ + OSL_ENSURE(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed,"Object wasn't disposed!"); + if(!ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed) + { + osl_atomic_increment( &m_refCount ); + dispose(); + } +} + +void ODatabaseMetaDataResultSet::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + + m_pConnection->freeStatementHandle(m_aStatementHandle); + + m_aStatement = nullptr; + m_xMetaData.clear(); + m_pConnection.clear(); +} + +Any SAL_CALL ODatabaseMetaDataResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + return aRet.hasValue() ? aRet : ODatabaseMetaDataResultSet_BASE::queryInterface(rType); +} + +Reference< XPropertySetInfo > SAL_CALL ODatabaseMetaDataResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +void SAL_CALL ODatabaseMetaDataResultSet::acquire() throw() +{ + ODatabaseMetaDataResultSet_BASE::acquire(); +} + +void SAL_CALL ODatabaseMetaDataResultSet::release() throw() +{ + ODatabaseMetaDataResultSet_BASE::release(); +} + +Sequence< Type > SAL_CALL ODatabaseMetaDataResultSet::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + + return ::comphelper::concatSequences(aTypes.getTypes(),ODatabaseMetaDataResultSet_BASE::getTypes()); +} + +sal_Int32 ODatabaseMetaDataResultSet::mapColumn (sal_Int32 column) +{ + sal_Int32 map = column; + + if (!m_aColMapping.empty()) + { + // Validate column number + map = m_aColMapping[column]; + } + + return map; +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::findColumn( const OUString& columnName ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + 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 ); + assert(false); + return 0; // Never reached +} + +template < typename T, SQLSMALLINT sqlTypeId > T ODatabaseMetaDataResultSet::getInteger ( sal_Int32 columnIndex ) +{ + ::cppu::OBroadcastHelper& rBHelper(ODatabaseMetaDataResultSet_BASE::rBHelper); + checkDisposed(rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + columnIndex = mapColumn(columnIndex); + T nVal = 0; + if(columnIndex <= m_nDriverColumnCount) + { + getValue<T>(m_pConnection.get(), m_aStatementHandle, columnIndex, sqlTypeId, m_bWasNull, **this, nVal); + + if ( !m_aValueRange.empty() ) + { + auto aValueRangeIter = m_aValueRange.find(columnIndex); + if ( aValueRangeIter != m_aValueRange.end() ) + return static_cast<T>(aValueRangeIter->second[nVal]); + } + } + else + m_bWasNull = true; + return nVal; +} + + +Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this ); + return nullptr; +} + +Reference< css::io::XInputStream > SAL_CALL ODatabaseMetaDataResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getCharacterStream", *this ); + return nullptr; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::getBoolean( sal_Int32 columnIndex ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + columnIndex = mapColumn(columnIndex); + + bool bRet = false; + if(columnIndex <= m_nDriverColumnCount) + { + sal_Int32 nType = getMetaData()->getColumnType(columnIndex); + switch(nType) + { + case DataType::BIT: + { + sal_Int8 nValue = 0; + OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_BIT,m_bWasNull,**this,&nValue,sizeof nValue); + bRet = nValue != 0; + } + break; + default: + bRet = getInt(columnIndex) != 0; + } + } + return bRet; +} + + +sal_Int8 SAL_CALL ODatabaseMetaDataResultSet::getByte( sal_Int32 columnIndex ) +{ + return getInteger<sal_Int8, SQL_C_STINYINT>( columnIndex ); +} + + +Sequence< sal_Int8 > SAL_CALL ODatabaseMetaDataResultSet::getBytes( sal_Int32 columnIndex ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + columnIndex = mapColumn(columnIndex); + if(columnIndex <= m_nDriverColumnCount) + { + sal_Int32 nType = getMetaData()->getColumnType(columnIndex); + switch(nType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + { + OUString const & aRet = OTools::getStringValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_BINARY,m_bWasNull,**this,m_nTextEncoding); + return Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),sizeof(sal_Unicode)*aRet.getLength()); + } + } + return OTools::getBytesValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_BINARY,m_bWasNull,**this); + } + else + m_bWasNull = true; + return Sequence<sal_Int8>(); +} + + +css::util::Date SAL_CALL ODatabaseMetaDataResultSet::getDate( sal_Int32 columnIndex ) +{ + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + columnIndex = mapColumn(columnIndex); + if(columnIndex <= m_nDriverColumnCount) + { + DATE_STRUCT aDate; + aDate.day = 0; + aDate.month = 0; + aDate.year = 0; + OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,m_pConnection->useOldDateFormat() ? SQL_C_DATE : SQL_C_TYPE_DATE,m_bWasNull,**this,&aDate,sizeof aDate); + return Date(aDate.day,aDate.month,aDate.year); + } + else + m_bWasNull = true; + return Date(); +} + + +double SAL_CALL ODatabaseMetaDataResultSet::getDouble( sal_Int32 columnIndex ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + columnIndex = mapColumn(columnIndex); + double nValue(0.0); + if(columnIndex <= m_nDriverColumnCount) + OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_DOUBLE,m_bWasNull,**this,&nValue,sizeof nValue); + else + m_bWasNull = true; + return nValue; +} + + +float SAL_CALL ODatabaseMetaDataResultSet::getFloat( sal_Int32 columnIndex ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + columnIndex = mapColumn(columnIndex); + float nVal(0); + if(columnIndex <= m_nDriverColumnCount) + OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,SQL_C_FLOAT,m_bWasNull,**this,&nVal,sizeof nVal); + else + m_bWasNull = true; + return nVal; +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getInt( sal_Int32 columnIndex ) +{ + return getInteger<sal_Int32, SQL_C_SLONG>( columnIndex ); +} + + +sal_Int32 SAL_CALL ODatabaseMetaDataResultSet::getRow( ) +{ + return 0; +} + + +sal_Int64 SAL_CALL ODatabaseMetaDataResultSet::getLong( sal_Int32 columnIndex ) +{ + return getInteger<sal_Int64, SQL_C_SBIGINT>( columnIndex ); +} + + +Reference< XResultSetMetaData > SAL_CALL ODatabaseMetaDataResultSet::getMetaData( ) +{ + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(m_pConnection.get(),m_aStatementHandle); + return m_xMetaData; +} + +Reference< XArray > SAL_CALL ODatabaseMetaDataResultSet::getArray( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this ); + return nullptr; +} + +Reference< XClob > SAL_CALL ODatabaseMetaDataResultSet::getClob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this ); + return nullptr; +} + +Reference< XBlob > SAL_CALL ODatabaseMetaDataResultSet::getBlob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this ); + return nullptr; +} + + +Reference< XRef > SAL_CALL ODatabaseMetaDataResultSet::getRef( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this ); + return nullptr; +} + + +Any SAL_CALL ODatabaseMetaDataResultSet::getObject( sal_Int32 /*columnIndex*/, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getObject", *this ); + return Any(); +} + + +sal_Int16 SAL_CALL ODatabaseMetaDataResultSet::getShort( sal_Int32 columnIndex ) +{ + return getInteger<sal_Int16, SQL_C_SSHORT>( columnIndex ); +} + + +OUString SAL_CALL ODatabaseMetaDataResultSet::getString( sal_Int32 columnIndex ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + columnIndex = mapColumn(columnIndex); + OUString aVal; + if(columnIndex <= m_nDriverColumnCount) + aVal = OTools::getStringValue(m_pConnection.get(),m_aStatementHandle,columnIndex,impl_getColumnType_nothrow(columnIndex),m_bWasNull,**this,m_nTextEncoding); + else + m_bWasNull = true; + + return aVal; +} + + +css::util::Time SAL_CALL ODatabaseMetaDataResultSet::getTime( sal_Int32 columnIndex ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + columnIndex = mapColumn(columnIndex); + TIME_STRUCT aTime={0,0,0}; + if(columnIndex <= m_nDriverColumnCount) + OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,m_pConnection->useOldDateFormat() ? SQL_C_TIME : SQL_C_TYPE_TIME,m_bWasNull,**this,&aTime,sizeof aTime); + else + m_bWasNull = true; + return Time(0, aTime.second,aTime.minute,aTime.hour, false); +} + + +css::util::DateTime SAL_CALL ODatabaseMetaDataResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + columnIndex = mapColumn(columnIndex); + TIMESTAMP_STRUCT aTime={0,0,0,0,0,0,0}; + if(columnIndex <= m_nDriverColumnCount) + OTools::getValue(m_pConnection.get(),m_aStatementHandle,columnIndex,m_pConnection->useOldDateFormat() ? SQL_C_TIMESTAMP : SQL_C_TYPE_TIMESTAMP, m_bWasNull, **this, &aTime, sizeof aTime); + else + m_bWasNull = true; + return DateTime(aTime.fraction, aTime.second, aTime.minute, aTime.hour, + aTime.day, aTime.month, aTime.year, false); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isAfterLast( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + return m_nCurrentFetchState == SQL_NO_DATA; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isFirst( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + return m_nRowPos == 1; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isLast( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + return m_bEOF && m_nCurrentFetchState != SQL_NO_DATA; +} + +void SAL_CALL ODatabaseMetaDataResultSet::beforeFirst( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + if(first()) + previous(); + m_nCurrentFetchState = SQL_SUCCESS; +} + +void SAL_CALL ODatabaseMetaDataResultSet::afterLast( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + if(last()) + next(); +} + + +void SAL_CALL ODatabaseMetaDataResultSet::close( ) +{ + { + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + } + dispose(); +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::first( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + m_bEOF = false; + + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_FIRST,0); + OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + bool bRet = ( m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO ); + if( bRet ) + m_nRowPos = 1; + return bRet; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::last( ) +{ + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed ); + ::osl::MutexGuard aGuard( m_aMutex ); + + + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_LAST,0); + OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + // here I know definitely that I stand on the last record + bool bRet = ( m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO ); + if( bRet ) + m_bEOF = true; + return bRet; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::absolute( sal_Int32 row ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + m_bEOF = false; + + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_ABSOLUTE,row); + OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + bool bRet = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO; + if(bRet) + m_nRowPos = row; + return bRet; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::relative( sal_Int32 row ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + m_bEOF = false; + + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_RELATIVE,row); + OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + bool bRet = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO; + if(bRet) + m_nRowPos += row; + return bRet; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::previous( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + m_bEOF = false; + + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_PRIOR,0); + OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + bool bRet = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO; + if(bRet) + --m_nRowPos; + else if ( m_nCurrentFetchState == SQL_NO_DATA ) + m_nRowPos = 0; + return bRet; +} + +Reference< XInterface > SAL_CALL ODatabaseMetaDataResultSet::getStatement( ) +{ + return nullptr; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowDeleted( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + return m_pRowStatusArray[0] == SQL_ROW_DELETED; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowInserted( ) +{ + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + return m_pRowStatusArray[0] == SQL_ROW_ADDED; +} + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::rowUpdated( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + return m_pRowStatusArray[0] == SQL_ROW_UPDATED; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::isBeforeFirst( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + return m_nRowPos == 0; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::next( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + m_bEOF = false; + + SQLRETURN nOldFetchStatus = m_nCurrentFetchState; + // m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_NEXT,0); + m_nCurrentFetchState = N3SQLFetch(m_aStatementHandle); + OTools::ThrowException(m_pConnection.get(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + bool bRet = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO; + if(bRet || ( m_nCurrentFetchState == SQL_NO_DATA && nOldFetchStatus != SQL_NO_DATA ) ) + ++m_nRowPos; + return bRet; +} + + +sal_Bool SAL_CALL ODatabaseMetaDataResultSet::wasNull( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + return m_bWasNull; +} + +void SAL_CALL ODatabaseMetaDataResultSet::refreshRow( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + +} + + +void SAL_CALL ODatabaseMetaDataResultSet::cancel( ) +{ + + checkDisposed(ODatabaseMetaDataResultSet_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + + N3SQLCancel(m_aStatementHandle); +} + +void SAL_CALL ODatabaseMetaDataResultSet::clearWarnings( ) +{ +} + +Any SAL_CALL ODatabaseMetaDataResultSet::getWarnings( ) +{ + return Any(); +} + +sal_Int32 ODatabaseMetaDataResultSet::getFetchSize() +{ + return 1; +} + +OUString ODatabaseMetaDataResultSet::getCursorName() +{ + return OUString(); +} + + +::cppu::IPropertyArrayHelper* ODatabaseMetaDataResultSet::createArrayHelper( ) const +{ + + Sequence< css::beans::Property > aProps(5); + css::beans::Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper & ODatabaseMetaDataResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool ODatabaseMetaDataResultSet::convertFastPropertyValue( + Any & rConvertedValue, + Any & rOldValue, + sal_Int32 nHandle, + const Any& rValue ) +{ + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection()); + case PROPERTY_ID_FETCHSIZE: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize()); + default: + ; + } + return false; +} + +void ODatabaseMetaDataResultSet::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& /*rValue*/ ) +{ + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + case PROPERTY_ID_FETCHDIRECTION: + case PROPERTY_ID_FETCHSIZE: + throw Exception("cannot set prop " + OUString::number(nHandle), nullptr); + default: + OSL_FAIL("setFastPropertyValue_NoBroadcast: Illegal handle value!"); + } +} + +void ODatabaseMetaDataResultSet::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + switch(nHandle) + { + case PROPERTY_ID_CURSORNAME: + rValue <<= getCursorName(); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= sal_Int32(css::sdbc::ResultSetConcurrency::READ_ONLY); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= sal_Int32(css::sdbc::ResultSetType::FORWARD_ONLY); + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= getFetchDirection(); + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= getFetchSize(); + break; + } +} + +void ODatabaseMetaDataResultSet::openTypeInfo() +{ + ::std::map<sal_Int32,sal_Int32> aMap; + aMap[SQL_BIT] = DataType::BIT; + aMap[SQL_TINYINT] = DataType::TINYINT; + aMap[SQL_SMALLINT] = DataType::SMALLINT; + aMap[SQL_INTEGER] = DataType::INTEGER; + aMap[SQL_FLOAT] = DataType::FLOAT; + aMap[SQL_REAL] = DataType::REAL; + aMap[SQL_DOUBLE] = DataType::DOUBLE; + aMap[SQL_BIGINT] = DataType::BIGINT; + + aMap[SQL_CHAR] = DataType::CHAR; + aMap[SQL_WCHAR] = DataType::CHAR; + aMap[SQL_VARCHAR] = DataType::VARCHAR; + aMap[SQL_WVARCHAR] = DataType::VARCHAR; + aMap[SQL_LONGVARCHAR] = DataType::LONGVARCHAR; + aMap[SQL_WLONGVARCHAR] = DataType::LONGVARCHAR; + + aMap[SQL_TYPE_DATE] = DataType::DATE; + aMap[SQL_DATE] = DataType::DATE; + aMap[SQL_TYPE_TIME] = DataType::TIME; + aMap[SQL_TIME] = DataType::TIME; + aMap[SQL_TYPE_TIMESTAMP] = DataType::TIMESTAMP; + aMap[SQL_TIMESTAMP] = DataType::TIMESTAMP; + + aMap[SQL_DECIMAL] = DataType::DECIMAL; + aMap[SQL_NUMERIC] = DataType::NUMERIC; + + aMap[SQL_BINARY] = DataType::BINARY; + aMap[SQL_VARBINARY] = DataType::VARBINARY; + aMap[SQL_LONGVARBINARY] = DataType::LONGVARBINARY; + + aMap[SQL_GUID] = DataType::VARBINARY; + + + m_aValueRange[2] = aMap; + + OTools::ThrowException(m_pConnection.get(),N3SQLGetTypeInfo(m_aStatementHandle, SQL_ALL_TYPES),m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openTables(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const Sequence< OUString >& types ) +{ + OString aPKQ,aPKO,aPKN,aCOL; + const OUString *pSchemaPat = nullptr; + + if(schemaPattern != "%") + pSchemaPat = &schemaPattern; + else + pSchemaPat = nullptr; + + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); + aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(); + + + const char *pCOL = nullptr; + const char* const pComma = ","; + const OUString* pBegin = types.getConstArray(); + const OUString* pEnd = pBegin + types.getLength(); + for(;pBegin != pEnd;++pBegin) + { + aCOL += OUStringToOString(*pBegin,m_nTextEncoding) + pComma; + } + if ( !aCOL.isEmpty() ) + { + aCOL = aCOL.replaceAt(aCOL.getLength()-1,1,pComma); + pCOL = aCOL.getStr(); + } + else + pCOL = SQL_ALL_TABLE_TYPES; + + SQLRETURN nRetcode = N3SQLTables(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), pCOL ? SQL_NTS : 0); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); + +} + +void ODatabaseMetaDataResultSet::openTablesTypes( ) +{ + SQLRETURN nRetcode = N3SQLTables(m_aStatementHandle, + nullptr,0, + nullptr,0, + nullptr,0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_TABLE_TYPES)),SQL_NTS); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + + m_aColMapping.clear(); + m_aColMapping.push_back(-1); + m_aColMapping.push_back(4); + m_xMetaData = new OResultSetMetaData(m_pConnection.get(),m_aStatementHandle,m_aColMapping); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openCatalogs() +{ + SQLRETURN nRetcode = N3SQLTables(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_CATALOGS)),SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS); + + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + + m_aColMapping.clear(); + m_aColMapping.push_back(-1); + m_aColMapping.push_back(1); + m_xMetaData = new OResultSetMetaData(m_pConnection.get(),m_aStatementHandle,m_aColMapping); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openSchemas() +{ + SQLRETURN nRetcode = N3SQLTables(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(SQL_ALL_SCHEMAS)),SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>("")),SQL_NTS); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + + m_aColMapping.clear(); + m_aColMapping.push_back(-1); + m_aColMapping.push_back(2); + m_xMetaData = new OResultSetMetaData(m_pConnection.get(),m_aStatementHandle,m_aColMapping); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openColumnPrivileges( const Any& catalog, const OUString& schema, + const OUString& table, const OUString& columnNamePattern ) +{ + const OUString *pSchemaPat = nullptr; + + if(schema != "%") + pSchemaPat = &schema; + else + pSchemaPat = nullptr; + + OString aPKQ,aPKO,aPKN,aCOL; + + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schema,m_nTextEncoding); + aPKN = OUStringToOString(table,m_nTextEncoding); + aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(), + *pCOL = aCOL.getStr(); + + + SQLRETURN nRetcode = N3SQLColumnPrivileges(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openColumns( const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, const OUString& columnNamePattern ) +{ + const OUString *pSchemaPat = nullptr; + + if(schemaPattern != "%") + pSchemaPat = &schemaPattern; + else + pSchemaPat = nullptr; + + OString aPKQ,aPKO,aPKN,aCOL; + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); + aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding); + aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(), + *pCOL = aCOL.getStr(); + + + SQLRETURN nRetcode = N3SQLColumns(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS); + + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + ::std::map<sal_Int32,sal_Int32> aMap; + aMap[SQL_BIT] = DataType::BIT; + aMap[SQL_TINYINT] = DataType::TINYINT; + aMap[SQL_SMALLINT] = DataType::SMALLINT; + aMap[SQL_INTEGER] = DataType::INTEGER; + aMap[SQL_FLOAT] = DataType::FLOAT; + aMap[SQL_REAL] = DataType::REAL; + aMap[SQL_DOUBLE] = DataType::DOUBLE; + aMap[SQL_BIGINT] = DataType::BIGINT; + + aMap[SQL_CHAR] = DataType::CHAR; + aMap[SQL_WCHAR] = DataType::CHAR; + aMap[SQL_VARCHAR] = DataType::VARCHAR; + aMap[SQL_WVARCHAR] = DataType::VARCHAR; + aMap[SQL_LONGVARCHAR] = DataType::LONGVARCHAR; + aMap[SQL_WLONGVARCHAR] = DataType::LONGVARCHAR; + + aMap[SQL_TYPE_DATE] = DataType::DATE; + aMap[SQL_DATE] = DataType::DATE; + aMap[SQL_TYPE_TIME] = DataType::TIME; + aMap[SQL_TIME] = DataType::TIME; + aMap[SQL_TYPE_TIMESTAMP] = DataType::TIMESTAMP; + aMap[SQL_TIMESTAMP] = DataType::TIMESTAMP; + + aMap[SQL_DECIMAL] = DataType::DECIMAL; + aMap[SQL_NUMERIC] = DataType::NUMERIC; + + aMap[SQL_BINARY] = DataType::BINARY; + aMap[SQL_VARBINARY] = DataType::VARBINARY; + aMap[SQL_LONGVARBINARY] = DataType::LONGVARBINARY; + + aMap[SQL_GUID] = DataType::VARBINARY; + + m_aValueRange[5] = aMap; + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openProcedureColumns( const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern,const OUString& columnNamePattern ) +{ + const OUString *pSchemaPat = nullptr; + + if(schemaPattern != "%") + pSchemaPat = &schemaPattern; + else + pSchemaPat = nullptr; + + OString aPKQ,aPKO,aPKN,aCOL; + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); + aPKN = OUStringToOString(procedureNamePattern,m_nTextEncoding); + aCOL = OUStringToOString(columnNamePattern,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(), + *pCOL = aCOL.getStr(); + + + SQLRETURN nRetcode = N3SQLProcedureColumns(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pCOL)), SQL_NTS); + + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openProcedures(const Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern) +{ + const OUString *pSchemaPat = nullptr; + + if(schemaPattern != "%") + pSchemaPat = &schemaPattern; + else + pSchemaPat = nullptr; + + OString aPKQ,aPKO,aPKN; + + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); + aPKN = OUStringToOString(procedureNamePattern,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(); + + + SQLRETURN nRetcode = N3SQLProcedures(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openSpecialColumns(bool _bRowVer,const Any& catalog, const OUString& schema, + const OUString& table,sal_Int32 scope, bool nullable ) +{ + // Some ODBC drivers really don't like getting an empty string as tableName + // E.g. psqlodbc up to at least version 09.01.0100 segfaults + if (table.isEmpty()) + { + const char errMsg[] = "ODBC: Trying to get special columns of empty table name"; + const char SQLState[] = "HY009"; + throw SQLException( errMsg, *this, SQLState, -1, Any() ); + } + + const OUString *pSchemaPat = nullptr; + + if(schema != "%") + pSchemaPat = &schema; + else + pSchemaPat = nullptr; + + OString aPKQ,aPKO,aPKN; + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schema,m_nTextEncoding); + aPKN = OUStringToOString(table,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(); + + + SQLRETURN nRetcode = N3SQLSpecialColumns(m_aStatementHandle,_bRowVer ? SQL_ROWVER : SQL_BEST_ROWID, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, + static_cast<SQLSMALLINT>(scope), + nullable ? SQL_NULLABLE : SQL_NO_NULLS); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openVersionColumns(const Any& catalog, const OUString& schema, + const OUString& table) +{ + openSpecialColumns(true,catalog,schema,table,SQL_SCOPE_TRANSACTION,false); +} + +void ODatabaseMetaDataResultSet::openBestRowIdentifier( const Any& catalog, const OUString& schema, + const OUString& table,sal_Int32 scope,bool nullable ) +{ + openSpecialColumns(false,catalog,schema,table,scope,nullable); +} + +void ODatabaseMetaDataResultSet::openForeignKeys( const Any& catalog, const OUString* schema, + const OUString* table, + const Any& catalog2, const OUString* schema2, + const OUString* table2) +{ + OString aPKQ, aPKO, aPKN, aFKQ, aFKO, aFKN; + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + if ( catalog2.hasValue() ) + aFKQ = OUStringToOString(comphelper::getString(catalog2),m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr; + const char *pPKO = nullptr; + if (schema && !schema->isEmpty()) + { + aPKO = OUStringToOString(*schema,m_nTextEncoding); + pPKO = aPKO.getStr(); + } + const char *pPKN = nullptr; + if (table) + { + aPKN = OUStringToOString(*table,m_nTextEncoding); + pPKN = aPKN.getStr(); + } + const char *pFKQ = catalog2.hasValue() && !aFKQ.isEmpty() ? aFKQ.getStr() : nullptr; + const char *pFKO = nullptr; + if (schema2 && !schema2->isEmpty()) + { + aFKO = OUStringToOString(*schema2,m_nTextEncoding); + pFKO = aFKO.getStr(); + } + const char *pFKN = nullptr; + if (table2) + { + aFKN = OUStringToOString(*table2,m_nTextEncoding); + pFKN = aFKN.getStr(); + } + + SQLRETURN nRetcode = N3SQLForeignKeys(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), pPKN ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKQ)), (catalog2.hasValue() && !aFKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKO)), pFKO ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pFKN)), SQL_NTS + ); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openImportedKeys(const Any& catalog, const OUString& schema, + const OUString& table) +{ + + openForeignKeys(Any(),nullptr,nullptr,catalog, schema == "%" ? &schema : nullptr, &table); +} + +void ODatabaseMetaDataResultSet::openExportedKeys(const Any& catalog, const OUString& schema, + const OUString& table) +{ + openForeignKeys(catalog, schema == "%" ? &schema : nullptr, &table,Any(),nullptr,nullptr); +} + +void ODatabaseMetaDataResultSet::openPrimaryKeys(const Any& catalog, const OUString& schema, + const OUString& table) +{ + const OUString *pSchemaPat = nullptr; + + if(schema != "%") + pSchemaPat = &schema; + else + pSchemaPat = nullptr; + + OString aPKQ,aPKO,aPKN; + + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schema,m_nTextEncoding); + aPKN = OUStringToOString(table,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(); + + + SQLRETURN nRetcode = N3SQLPrimaryKeys(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openTablePrivileges(const Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern) +{ + const OUString *pSchemaPat = nullptr; + + if(schemaPattern != "%") + pSchemaPat = &schemaPattern; + else + pSchemaPat = nullptr; + + OString aPKQ,aPKO,aPKN; + + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schemaPattern,m_nTextEncoding); + aPKN = OUStringToOString(tableNamePattern,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(); + + SQLRETURN nRetcode = N3SQLTablePrivileges(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::openIndexInfo( const Any& catalog, const OUString& schema, + const OUString& table, bool unique, bool approximate ) +{ + const OUString *pSchemaPat = nullptr; + + if(schema != "%") + pSchemaPat = &schema; + else + pSchemaPat = nullptr; + + OString aPKQ,aPKO,aPKN; + + if ( catalog.hasValue() ) + aPKQ = OUStringToOString(comphelper::getString(catalog),m_nTextEncoding); + aPKO = OUStringToOString(schema,m_nTextEncoding); + aPKN = OUStringToOString(table,m_nTextEncoding); + + const char *pPKQ = catalog.hasValue() && !aPKQ.isEmpty() ? aPKQ.getStr() : nullptr, + *pPKO = pSchemaPat && !pSchemaPat->isEmpty() && !aPKO.isEmpty() ? aPKO.getStr() : nullptr, + *pPKN = aPKN.getStr(); + + SQLRETURN nRetcode = N3SQLStatistics(m_aStatementHandle, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKQ)), (catalog.hasValue() && !aPKQ.isEmpty()) ? SQL_NTS : 0, + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKO)), pPKO ? SQL_NTS : 0 , + reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(pPKN)), SQL_NTS, + unique ? SQL_INDEX_UNIQUE : SQL_INDEX_ALL, + approximate ? 1 : 0); + OTools::ThrowException(m_pConnection.get(),nRetcode,m_aStatementHandle,SQL_HANDLE_STMT,*this); + checkColumnCount(); +} + +void ODatabaseMetaDataResultSet::checkColumnCount() +{ + sal_Int16 nNumResultCols=0; + OTools::ThrowException(m_pConnection.get(),N3SQLNumResultCols(m_aStatementHandle,&nNumResultCols),m_aStatementHandle,SQL_HANDLE_STMT,*this); + m_nDriverColumnCount = nNumResultCols; +} + + +SWORD ODatabaseMetaDataResultSet::impl_getColumnType_nothrow(sal_Int32 columnIndex) +{ + std::map<sal_Int32,SWORD>::iterator aFind = m_aODBCColumnTypes.find(columnIndex); + if ( aFind == m_aODBCColumnTypes.end() ) + aFind = m_aODBCColumnTypes.emplace( + columnIndex, + OResultSetMetaData::getColumnODBCType(m_pConnection.get(),m_aStatementHandle,*this,columnIndex) + ).first; + return aFind->second; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/ODriver.cxx b/connectivity/source/drivers/odbc/ODriver.cxx new file mode 100644 index 000000000..376946d02 --- /dev/null +++ b/connectivity/source/drivers/odbc/ODriver.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 <odbc/ODriver.hxx> +#include <odbc/OConnection.hxx> +#include <odbc/OTools.hxx> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + +using namespace connectivity::odbc; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + +ODBCDriver::ODBCDriver(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory) + :ODriver_BASE(m_aMutex) + ,m_xORB(_rxFactory) + ,m_pDriverHandle(SQL_NULL_HANDLE) +{ +} + +void ODBCDriver::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + + for (auto const& connection : m_xConnections) + { + Reference< XComponent > xComp(connection.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + } + m_xConnections.clear(); + + ODriver_BASE::disposing(); +} + +// static ServiceInfo + +OUString ODBCDriver::getImplementationName_Static( ) +{ + return "com.sun.star.comp.sdbc.ODBCDriver"; + // this name is referenced in the configuration and in the odbc.xml + // Please take care when changing it. +} + + +Sequence< OUString > ODBCDriver::getSupportedServiceNames_Static( ) +{ + Sequence<OUString> aSNS { "com.sun.star.sdbc.Driver" }; + return aSNS; +} + + +OUString SAL_CALL ODBCDriver::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL ODBCDriver::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +Sequence< OUString > SAL_CALL ODBCDriver::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + + +Reference< XConnection > SAL_CALL ODBCDriver::connect( const OUString& url, const Sequence< PropertyValue >& info ) +{ + if ( ! acceptsURL(url) ) + return nullptr; + + if(!m_pDriverHandle) + { + OUString aPath; + if(!EnvironmentHandle(aPath)) + throw SQLException(aPath,*this,OUString(),1000,Any()); + } + OConnection* pCon = new OConnection(m_pDriverHandle,this); + Reference< XConnection > xCon = pCon; + pCon->Construct(url,info); + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + + return xCon; +} + +sal_Bool SAL_CALL ODBCDriver::acceptsURL( const OUString& url ) +{ + return url.startsWith("sdbc:odbc:"); +} + +Sequence< DriverPropertyInfo > SAL_CALL ODBCDriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ ) +{ + if ( acceptsURL(url) ) + { + std::vector< DriverPropertyInfo > aDriverInfo; + + Sequence< OUString > aBooleanValues(2); + aBooleanValues[0] = "false"; + aBooleanValues[1] = "true"; + + aDriverInfo.push_back(DriverPropertyInfo( + "CharSet" + ,"CharSet of the database." + ,false + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "UseCatalog" + ,"Use catalog for file-based databases." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "SystemDriverSettings" + ,"Driver settings." + ,false + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "ParameterNameSubstitution" + ,"Change named parameters with '?'." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "IgnoreDriverPrivileges" + ,"Ignore the privileges from the database driver." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "IsAutoRetrievingEnabled" + ,"Retrieve generated values." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "AutoRetrievingStatement" + ,"Auto-increment statement." + ,false + ,OUString() + ,Sequence< OUString >()) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "GenerateASBeforeCorrelationName" + ,"Generate AS before table correlation names." + ,false + ,"false" + ,aBooleanValues) + ); + aDriverInfo.push_back(DriverPropertyInfo( + "EscapeDateTime" + ,"Escape date time format." + ,false + ,"true" + ,aBooleanValues) + ); + + return Sequence< DriverPropertyInfo >(aDriverInfo.data(),aDriverInfo.size()); + } + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + return Sequence< DriverPropertyInfo >(); +} + +sal_Int32 SAL_CALL ODBCDriver::getMajorVersion( ) +{ + return 1; +} + +sal_Int32 SAL_CALL ODBCDriver::getMinorVersion( ) +{ + return 0; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/OFunctions.cxx b/connectivity/source/drivers/odbc/OFunctions.cxx new file mode 100644 index 000000000..ae8953176 --- /dev/null +++ b/connectivity/source/drivers/odbc/OFunctions.cxx @@ -0,0 +1,243 @@ +/* -*- 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 <odbc/OFunctions.hxx> + +// Implib definitions for ODBC-DLL/shared library: + +namespace connectivity +{ + T3SQLAllocHandle pODBC3SQLAllocHandle; +T3SQLConnect pODBC3SQLConnect; +T3SQLDriverConnect pODBC3SQLDriverConnect; +T3SQLBrowseConnect pODBC3SQLBrowseConnect; +T3SQLDataSources pODBC3SQLDataSources; +T3SQLDrivers pODBC3SQLDrivers; +T3SQLGetInfo pODBC3SQLGetInfo; +T3SQLGetFunctions pODBC3SQLGetFunctions; +T3SQLGetTypeInfo pODBC3SQLGetTypeInfo; +T3SQLSetConnectAttr pODBC3SQLSetConnectAttr; +T3SQLGetConnectAttr pODBC3SQLGetConnectAttr; +T3SQLSetEnvAttr pODBC3SQLSetEnvAttr; +T3SQLGetEnvAttr pODBC3SQLGetEnvAttr; +T3SQLSetStmtAttr pODBC3SQLSetStmtAttr; +T3SQLGetStmtAttr pODBC3SQLGetStmtAttr; +T3SQLPrepare pODBC3SQLPrepare; +T3SQLBindParameter pODBC3SQLBindParameter; +T3SQLSetCursorName pODBC3SQLSetCursorName; +T3SQLExecute pODBC3SQLExecute; +T3SQLExecDirect pODBC3SQLExecDirect; +T3SQLDescribeParam pODBC3SQLDescribeParam; +T3SQLNumParams pODBC3SQLNumParams; +T3SQLParamData pODBC3SQLParamData; +T3SQLPutData pODBC3SQLPutData; +T3SQLRowCount pODBC3SQLRowCount; +T3SQLNumResultCols pODBC3SQLNumResultCols; +T3SQLDescribeCol pODBC3SQLDescribeCol; +T3SQLColAttribute pODBC3SQLColAttribute; +T3SQLBindCol pODBC3SQLBindCol; +T3SQLFetch pODBC3SQLFetch; +T3SQLFetchScroll pODBC3SQLFetchScroll; +T3SQLGetData pODBC3SQLGetData; +T3SQLSetPos pODBC3SQLSetPos; +T3SQLBulkOperations pODBC3SQLBulkOperations; +T3SQLMoreResults pODBC3SQLMoreResults; +T3SQLGetDiagRec pODBC3SQLGetDiagRec; +T3SQLColumnPrivileges pODBC3SQLColumnPrivileges; +T3SQLColumns pODBC3SQLColumns; +T3SQLForeignKeys pODBC3SQLForeignKeys; +T3SQLPrimaryKeys pODBC3SQLPrimaryKeys; +T3SQLProcedureColumns pODBC3SQLProcedureColumns; +T3SQLProcedures pODBC3SQLProcedures; +T3SQLSpecialColumns pODBC3SQLSpecialColumns; +T3SQLStatistics pODBC3SQLStatistics; +T3SQLTablePrivileges pODBC3SQLTablePrivileges; +T3SQLTables pODBC3SQLTables; +T3SQLFreeStmt pODBC3SQLFreeStmt; +T3SQLCloseCursor pODBC3SQLCloseCursor; +T3SQLCancel pODBC3SQLCancel; +T3SQLEndTran pODBC3SQLEndTran; +T3SQLDisconnect pODBC3SQLDisconnect; +T3SQLFreeHandle pODBC3SQLFreeHandle; +T3SQLGetCursorName pODBC3SQLGetCursorName; +T3SQLNativeSql pODBC3SQLNativeSql; + +static bool LoadFunctions(oslModule pODBCso); + +// Take care of Dynamically loading of the DLL/shared lib and Addresses: +// Returns sal_True at success +bool LoadLibrary_ODBC3(OUString &_rPath) +{ + static bool bLoaded = false; + static oslModule pODBCso = nullptr; + + if (bLoaded) + return true; +#ifndef DISABLE_DYNLOADING +#ifdef _WIN32 + _rPath = "ODBC32.DLL"; +#endif +#ifdef UNX + #ifdef MACOSX + _rPath = "libiodbc.dylib"; + #else + _rPath = "libodbc.so.2"; + pODBCso = osl_loadModule( _rPath.pData,SAL_LOADMODULE_NOW ); + if ( !pODBCso ) + { + _rPath = "libodbc.so.1"; + pODBCso = osl_loadModule( _rPath.pData,SAL_LOADMODULE_NOW ); + } + if ( !pODBCso ) + _rPath = "libodbc.so"; + + #endif /* MACOSX */ +#endif + + if ( !pODBCso ) + pODBCso = osl_loadModule( _rPath.pData,SAL_LOADMODULE_NOW ); +#endif + if( !pODBCso) + return false; + + bLoaded = LoadFunctions(pODBCso); + return bLoaded; +} + + +bool LoadFunctions(oslModule pODBCso) +{ + + if( ( pODBC3SQLAllocHandle = reinterpret_cast<T3SQLAllocHandle>(osl_getFunctionSymbol(pODBCso, OUString("SQLAllocHandle").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLConnect = reinterpret_cast<T3SQLConnect>(osl_getFunctionSymbol(pODBCso, OUString("SQLConnect").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLDriverConnect = reinterpret_cast<T3SQLDriverConnect>(osl_getFunctionSymbol(pODBCso, OUString("SQLDriverConnect").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLBrowseConnect = reinterpret_cast<T3SQLBrowseConnect>(osl_getFunctionSymbol(pODBCso, OUString("SQLBrowseConnect").pData ))) == nullptr ) + return false; + if(( pODBC3SQLDataSources = reinterpret_cast<T3SQLDataSources>(osl_getFunctionSymbol(pODBCso, OUString("SQLDataSources").pData ))) == nullptr ) + return false; + if(( pODBC3SQLDrivers = reinterpret_cast<T3SQLDrivers>(osl_getFunctionSymbol(pODBCso, OUString("SQLDrivers").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLGetInfo = reinterpret_cast<T3SQLGetInfo>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetInfo").pData ))) == nullptr ) + return false; + if(( pODBC3SQLGetFunctions = reinterpret_cast<T3SQLGetFunctions>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetFunctions").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLGetTypeInfo = reinterpret_cast<T3SQLGetTypeInfo>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetTypeInfo").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLSetConnectAttr = reinterpret_cast<T3SQLSetConnectAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetConnectAttr").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLGetConnectAttr = reinterpret_cast<T3SQLGetConnectAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetConnectAttr").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLSetEnvAttr = reinterpret_cast<T3SQLSetEnvAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetEnvAttr").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLGetEnvAttr = reinterpret_cast<T3SQLGetEnvAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetEnvAttr").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLSetStmtAttr = reinterpret_cast<T3SQLSetStmtAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetStmtAttr").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLGetStmtAttr = reinterpret_cast<T3SQLGetStmtAttr>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetStmtAttr").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLPrepare = reinterpret_cast<T3SQLPrepare>(osl_getFunctionSymbol(pODBCso, OUString("SQLPrepare").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLBindParameter = reinterpret_cast<T3SQLBindParameter>(osl_getFunctionSymbol(pODBCso, OUString("SQLBindParameter").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLSetCursorName = reinterpret_cast<T3SQLSetCursorName>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetCursorName").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLExecute = reinterpret_cast<T3SQLExecute>(osl_getFunctionSymbol(pODBCso, OUString("SQLExecute").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLExecDirect = reinterpret_cast<T3SQLExecDirect>(osl_getFunctionSymbol(pODBCso, OUString("SQLExecDirect").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLDescribeParam = reinterpret_cast<T3SQLDescribeParam>(osl_getFunctionSymbol(pODBCso, OUString("SQLDescribeParam").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLNumParams = reinterpret_cast<T3SQLNumParams>(osl_getFunctionSymbol(pODBCso, OUString("SQLNumParams").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLParamData = reinterpret_cast<T3SQLParamData>(osl_getFunctionSymbol(pODBCso, OUString("SQLParamData").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLPutData = reinterpret_cast<T3SQLPutData>(osl_getFunctionSymbol(pODBCso, OUString("SQLPutData").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLRowCount = reinterpret_cast<T3SQLRowCount>(osl_getFunctionSymbol(pODBCso, OUString("SQLRowCount").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLNumResultCols = reinterpret_cast<T3SQLNumResultCols>(osl_getFunctionSymbol(pODBCso, OUString("SQLNumResultCols").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLDescribeCol = reinterpret_cast<T3SQLDescribeCol>(osl_getFunctionSymbol(pODBCso, OUString("SQLDescribeCol").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLColAttribute = reinterpret_cast<T3SQLColAttribute>(osl_getFunctionSymbol(pODBCso, OUString("SQLColAttribute").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLBindCol = reinterpret_cast<T3SQLBindCol>(osl_getFunctionSymbol(pODBCso, OUString("SQLBindCol").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLFetch = reinterpret_cast<T3SQLFetch>(osl_getFunctionSymbol(pODBCso, OUString("SQLFetch").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLFetchScroll = reinterpret_cast<T3SQLFetchScroll>(osl_getFunctionSymbol(pODBCso, OUString("SQLFetchScroll").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLGetData = reinterpret_cast<T3SQLGetData>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetData").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLSetPos = reinterpret_cast<T3SQLSetPos>(osl_getFunctionSymbol(pODBCso, OUString("SQLSetPos").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLBulkOperations = reinterpret_cast<T3SQLBulkOperations>(osl_getFunctionSymbol(pODBCso, OUString("SQLBulkOperations").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLMoreResults = reinterpret_cast<T3SQLMoreResults>(osl_getFunctionSymbol(pODBCso, OUString("SQLMoreResults").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLGetDiagRec = reinterpret_cast<T3SQLGetDiagRec>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetDiagRec").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLColumnPrivileges = reinterpret_cast<T3SQLColumnPrivileges>(osl_getFunctionSymbol(pODBCso, OUString("SQLColumnPrivileges").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLColumns = reinterpret_cast<T3SQLColumns>(osl_getFunctionSymbol(pODBCso, OUString("SQLColumns").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLForeignKeys = reinterpret_cast<T3SQLForeignKeys>(osl_getFunctionSymbol(pODBCso, OUString("SQLForeignKeys").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLPrimaryKeys = reinterpret_cast<T3SQLPrimaryKeys>(osl_getFunctionSymbol(pODBCso, OUString("SQLPrimaryKeys").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLProcedureColumns = reinterpret_cast<T3SQLProcedureColumns>(osl_getFunctionSymbol(pODBCso, OUString("SQLProcedureColumns").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLProcedures = reinterpret_cast<T3SQLProcedures>(osl_getFunctionSymbol(pODBCso, OUString("SQLProcedures").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLSpecialColumns = reinterpret_cast<T3SQLSpecialColumns>(osl_getFunctionSymbol(pODBCso, OUString("SQLSpecialColumns").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLStatistics = reinterpret_cast<T3SQLStatistics>(osl_getFunctionSymbol(pODBCso, OUString("SQLStatistics").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLTablePrivileges = reinterpret_cast<T3SQLTablePrivileges>(osl_getFunctionSymbol(pODBCso, OUString("SQLTablePrivileges").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLTables = reinterpret_cast<T3SQLTables>(osl_getFunctionSymbol(pODBCso, OUString("SQLTables").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLFreeStmt = reinterpret_cast<T3SQLFreeStmt>(osl_getFunctionSymbol(pODBCso, OUString("SQLFreeStmt").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLCloseCursor = reinterpret_cast<T3SQLCloseCursor>(osl_getFunctionSymbol(pODBCso, OUString("SQLCloseCursor").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLCancel = reinterpret_cast<T3SQLCancel>(osl_getFunctionSymbol(pODBCso, OUString("SQLCancel").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLEndTran = reinterpret_cast<T3SQLEndTran>(osl_getFunctionSymbol(pODBCso, OUString("SQLEndTran").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLDisconnect = reinterpret_cast<T3SQLDisconnect>(osl_getFunctionSymbol(pODBCso, OUString("SQLDisconnect").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLFreeHandle = reinterpret_cast<T3SQLFreeHandle>(osl_getFunctionSymbol(pODBCso, OUString("SQLFreeHandle").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLGetCursorName = reinterpret_cast<T3SQLGetCursorName>(osl_getFunctionSymbol(pODBCso, OUString("SQLGetCursorName").pData ))) == nullptr ) + return false; + if( ( pODBC3SQLNativeSql = reinterpret_cast<T3SQLNativeSql>(osl_getFunctionSymbol(pODBCso, OUString("SQLNativeSql").pData ))) == nullptr ) + return false; + + return true; +} + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/OPreparedStatement.cxx b/connectivity/source/drivers/odbc/OPreparedStatement.cxx new file mode 100644 index 000000000..65cfbf5e7 --- /dev/null +++ b/connectivity/source/drivers/odbc/OPreparedStatement.cxx @@ -0,0 +1,925 @@ +/* -*- 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 <osl/diagnose.h> +#include <odbc/OPreparedStatement.hxx> +#include <odbc/OBoundParam.hxx> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <odbc/OTools.hxx> +#include <odbc/OResultSet.hxx> +#include <odbc/OResultSetMetaData.hxx> +#include <comphelper/sequence.hxx> +#include <connectivity/dbtools.hxx> +#include <comphelper/types.hxx> +#include <connectivity/FValue.hxx> +#include <strings.hrc> +#include <memory> +#include <type_traits> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::odbc; +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.OPreparedStatement","com.sun.star.sdbc.PreparedStatement"); + +namespace +{ + // for now, never use wchar, + // but most of code is prepared to handle it + // in case we make this configurable + const bool bUseWChar = false; +} + +OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const OUString& sql) + :OStatement_BASE2(_pConnection) + ,numParams(0) + ,m_bPrepared(false) +{ + m_sSqlStatement = sql; +} + +OPreparedStatement::~OPreparedStatement() +{ +} + +void SAL_CALL OPreparedStatement::acquire() throw() +{ + OStatement_BASE2::acquire(); +} + +void SAL_CALL OPreparedStatement::release() throw() +{ + OStatement_BASE2::release(); +} + +Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType ) +{ + Any aRet = OStatement_BASE2::queryInterface(rType); + return aRet.hasValue() ? aRet : OPreparedStatement_BASE::queryInterface(rType); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( ) +{ + return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OStatement_BASE2::getTypes()); +} + + +Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + prepareStatement(); + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(getOwnConnection(),m_aStatementHandle); + return m_xMetaData; +} + + +void SAL_CALL OPreparedStatement::close( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + // Close/clear our result set + clearMyResultSet (); + + // Reset last warning message + + try { + clearWarnings (); + OStatement_BASE2::close(); + FreeParams(); + } + catch (SQLException &) { + // If we get an error, ignore + } + + // Remove this Statement object from the Connection object's + // list +} + + +sal_Bool SAL_CALL OPreparedStatement::execute( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + // Reset warnings + + clearWarnings (); + + // Reset the statement handle, warning and saved Resultset + + reset(); + + // Call SQLExecute + prepareStatement(); + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + try + { + SQLRETURN nReturn = N3SQLExecute(m_aStatementHandle); + + OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this); + bool needData = nReturn == SQL_NEED_DATA; + + // Now loop while more data is needed (i.e. a data-at- + // execution parameter was given). For each parameter + // that needs data, put the data from the input stream. + + while (needData) { + + // Get the parameter number that requires data + + sal_Int32* paramIndex = nullptr; + N3SQLParamData(m_aStatementHandle, reinterpret_cast<SQLPOINTER*>(¶mIndex)); + + // If the parameter index is -1, there is no + // more data required + + if ( !paramIndex || ( *paramIndex == -1 ) ) + needData = false; + else + { + // Now we have the proper parameter + // index, get the data from the input + // stream and do a SQLPutData + putParamData (*paramIndex); + } + } + + } + catch (const SQLWarning&) + { + } + + // Now determine if there is a result set associated with + // the SQL statement that was executed. Get the column + // count, and if it is not zero, there is a result set. + + + return getColumnCount() > 0; +} + + +sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + sal_Int32 numRows = -1; + + prepareStatement(); + // Execute the statement. If execute returns sal_False, a + // row count exists. + + if (!execute()) + numRows = getUpdateCount (); + else + { + // No update count was produced (a ResultSet was). Raise + // an exception + m_pConnection->throwGenericSQLException(STR_NO_ROWCOUNT,*this); + } + return numRows; +} + + +void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ + setParameter(parameterIndex, DataType::CHAR, invalid_scale, x); +} + + +Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + return Reference< XConnection >(m_pConnection.get()); +} + + +Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + Reference< XResultSet > rs; + + prepareStatement(); + + if (execute()) + rs = getResultSet(false); + else + { + // No ResultSet was produced. Raise an exception + m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this); + } + return rs; +} + + +void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) +{ + // Set the parameter as if it were an integer + setInt (parameterIndex, x ? 1 : 0 ); +} + +// The MutexGuard must _already_ be taken! +void OPreparedStatement::setParameterPre(sal_Int32 parameterIndex) +{ + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + prepareStatement(); + checkParameterIndex(parameterIndex); + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); +} + + +template <typename T> void OPreparedStatement::setScalarParameter(const sal_Int32 parameterIndex, const sal_Int32 i_nType, const SQLULEN i_nColSize, const T i_Value) +{ + setScalarParameter(parameterIndex, i_nType, i_nColSize, invalid_scale, i_Value); +} + + +template <typename T> void OPreparedStatement::setScalarParameter(const sal_Int32 parameterIndex, const sal_Int32 i_nType, const SQLULEN i_nColSize, sal_Int32 i_nScale, const T i_Value) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + setParameterPre(parameterIndex); + + typedef typename std::remove_reference<T>::type TnoRef; + + TnoRef *bindBuf = static_cast< TnoRef* >( allocBindBuf(parameterIndex, sizeof(i_Value)) ); + *bindBuf = i_Value; + + setParameter(parameterIndex, i_nType, i_nColSize, i_nScale, bindBuf, sizeof(i_Value), sizeof(i_Value)); +} + + +void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const sal_Int16 _nScale, const OUString &_sData) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + setParameterPre(parameterIndex); + + assert (_nType == DataType::VARCHAR || _nType == DataType::CHAR || _nType == DataType::DECIMAL || _nType == DataType::NUMERIC); + + sal_Int32 nCharLen; + sal_Int32 nByteLen; + void *pData; + if (bUseWChar) + { + /* + * On Windows, wchar is 16 bits (UTF-16 encoding), the ODBC "W" variants functions take UTF-16 encoded strings + * and character lengths are number of UTF-16 codepoints. + * Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms716246%28v=vs.85%29.aspx + * ODBC Programmer's reference > Developing Applications > Programming Considerations > Unicode > Unicode Function Arguments + * http://support.microsoft.com/kb/294169 + * + * UnixODBC can be configured at compile-time so that the "W" variants expect + * UTF-16 or UTF-32 encoded strings, and character lengths are number of codepoints. + * However, UTF-16 is the default, what all/most distributions do + * and the established API that most drivers implement. + * As wchar is often 32 bits, this differs from C-style strings of wchar! + * + * On MacOS X, the "W" variants use wchar_t, which is UCS4 + * + * Our internal OUString storage is always UTF-16, so no conversion to do here. + */ + static_assert(sizeof (SQLWCHAR) == 2 || sizeof (SQLWCHAR) == 4, "must be 2 or 4"); + if (sizeof (SQLWCHAR) == 2) + { + nCharLen = _sData.getLength(); + nByteLen = 2 * nCharLen; + pData = allocBindBuf(parameterIndex, nByteLen); + memcpy(pData, _sData.getStr(), nByteLen); + } + else + { + pData = allocBindBuf(parameterIndex, _sData.getLength() * 4); + sal_uInt32* pCursor = static_cast<sal_uInt32*>(pData); + nCharLen = 0; + for (sal_Int32 i = 0; i != _sData.getLength();) + { + *pCursor++ = _sData.iterateCodePoints(&i); + nCharLen += 1; + } + nByteLen = 4 * nCharLen; + } + } + else + { + assert(getOwnConnection()->getTextEncoding() != RTL_TEXTENCODING_UCS2 && + getOwnConnection()->getTextEncoding() != RTL_TEXTENCODING_UCS4); + OString sOData( + OUStringToOString(_sData, getOwnConnection()->getTextEncoding())); + nCharLen = nByteLen = sOData.getLength(); + pData = allocBindBuf(parameterIndex, nByteLen); + memcpy(pData, sOData.getStr(), nByteLen); + } + + setParameter( parameterIndex, _nType, nCharLen, _nScale, pData, nByteLen, nByteLen ); +} + +void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const Sequence< sal_Int8 > &x) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + setParameterPre(parameterIndex); + + assert(_nType == DataType::BINARY || _nType == DataType::VARBINARY); + + // don't copy the sequence, just point the ODBC directly at the sequence's storage array + // Why BINARY/Sequence is treated differently than strings (which are copied), I'm not sure + OSL_VERIFY(allocBindBuf(parameterIndex, 0) == nullptr); + boundParams[parameterIndex-1].setSequence(x); // this ensures that the sequence stays alive + + setParameter( parameterIndex, _nType, x.getLength(), invalid_scale, x.getConstArray(), x.getLength(), x.getLength() ); +} + +void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const SQLULEN _nColumnSize, const sal_Int32 _nScale, const void* const _pData, const SQLULEN _nDataLen, const SQLLEN _nDataAllocLen) +{ + SQLSMALLINT fCType, fSqlType; + OTools::getBindTypes(bUseWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType); + + SQLLEN& rDataLen = boundParams[parameterIndex-1].getBindLengthBuffer(); + rDataLen = _nDataLen; + + SQLRETURN nRetcode; + nRetcode = (*reinterpret_cast<T3SQLBindParameter>(m_pConnection->getOdbcFunction(ODBC3SQLFunctionId::BindParameter)))( + m_aStatementHandle, + // checkParameterIndex guarantees this is safe + static_cast<SQLUSMALLINT>(parameterIndex), + SQL_PARAM_INPUT, + fCType, + fSqlType, + _nColumnSize, + _nScale, + // we trust the ODBC driver not to touch it because SQL_PARAM_INPUT + const_cast<void*>(_pData), + _nDataAllocLen, + &rDataLen); + + OTools::ThrowException(m_pConnection.get(), nRetcode, m_aStatementHandle, SQL_HANDLE_STMT, *this); +} + +void SAL_CALL OPreparedStatement::setByte( const sal_Int32 parameterIndex, const sal_Int8 x ) +{ + setScalarParameter(parameterIndex, DataType::TINYINT, 3, 0, x); +} + +void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const Date& aData ) +{ + DATE_STRUCT x(OTools::DateToOdbcDate(aData)); + setScalarParameter<DATE_STRUCT&>(parameterIndex, DataType::DATE, 10, x); +} + +void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& aVal ) +{ + SQLULEN nColSize; + if(aVal.NanoSeconds == 0) + nColSize = 8; + else if(aVal.NanoSeconds % 100000000 == 0) + nColSize = 10; + else if(aVal.NanoSeconds % 10000000 == 0) + nColSize = 11; + else if(aVal.NanoSeconds % 1000000 == 0) + nColSize = 12; + else if(aVal.NanoSeconds % 100000 == 0) + nColSize = 13; + else if(aVal.NanoSeconds % 10000 == 0) + nColSize = 14; + else if(aVal.NanoSeconds % 1000 == 0) + nColSize = 15; + else if(aVal.NanoSeconds % 100 == 0) + nColSize = 16; + else if(aVal.NanoSeconds % 10 == 0) + nColSize = 17; + else + nColSize = 18; + TIME_STRUCT x(OTools::TimeToOdbcTime(aVal)); + setScalarParameter<TIME_STRUCT&>(parameterIndex, DataType::TIME, nColSize, (nColSize == 8)? 0 : nColSize-9, x); +} + + +void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const DateTime& aVal ) +{ + SQLULEN nColSize; + if(aVal.NanoSeconds == 0) + { + if (aVal.Seconds == 0) + nColSize=16; + else + nColSize=19; + } + else if(aVal.NanoSeconds % 100000000 == 0) + nColSize = 21; + else if(aVal.NanoSeconds % 10000000 == 0) + nColSize = 22; + else if(aVal.NanoSeconds % 1000000 == 0) + nColSize = 23; + else if(aVal.NanoSeconds % 100000 == 0) + nColSize = 24; + else if(aVal.NanoSeconds % 10000 == 0) + nColSize = 25; + else if(aVal.NanoSeconds % 1000 == 0) + nColSize = 26; + else if(aVal.NanoSeconds % 100 == 0) + nColSize = 27; + else if(aVal.NanoSeconds % 10 == 0) + nColSize = 28; + else + nColSize = 29; + + TIMESTAMP_STRUCT x(OTools::DateTimeToTimestamp(aVal)); + setScalarParameter<TIMESTAMP_STRUCT&>(parameterIndex, DataType::TIMESTAMP, nColSize, (nColSize <= 19)? 0 : nColSize-20, x); +} + + +void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) +{ + setScalarParameter(parameterIndex, DataType::DOUBLE, 15, x); +} + + +void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) +{ + setScalarParameter(parameterIndex, DataType::FLOAT, 15, x); +} + + +void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) +{ + setScalarParameter(parameterIndex, DataType::INTEGER, 10, 0, x); +} + + +void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) +{ + try + { + setScalarParameter(parameterIndex, DataType::BIGINT, 19, 0, x); + } + catch(SQLException&) + { + setString(parameterIndex, ORowSetValue(x)); + } +} + + +void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, const sal_Int32 _nType ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + setParameterPre(parameterIndex); + + OSL_VERIFY(allocBindBuf(parameterIndex, 0) == nullptr); + SQLLEN * const lenBuf = getLengthBuf (parameterIndex); + *lenBuf = SQL_NULL_DATA; + + + SQLSMALLINT fCType; + SQLSMALLINT fSqlType; + + OTools::getBindTypes( bUseWChar, + m_pConnection->useOldDateFormat(), + OTools::jdbcTypeToOdbc(_nType), + fCType, + fSqlType); + + SQLRETURN nReturn = N3SQLBindParameter( m_aStatementHandle, + static_cast<SQLUSMALLINT>(parameterIndex), + SQL_PARAM_INPUT, + fCType, + fSqlType, + 0, + 0, + nullptr, + 0, + lenBuf + ); + OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this); +} + + +void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x ) +{ + if ( x.is() ) + setStream(parameterIndex, x->getCharacterStream(), x->length(), DataType::LONGVARCHAR); +} + + +void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x ) +{ + if ( x.is() ) + setStream(parameterIndex, x->getBinaryStream(), x->length(), DataType::LONGVARBINARY); +} + + +void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setArray", *this ); +} + + +void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setRef", *this ); +} + +void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) +{ + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + prepareStatement(); + // For each known SQL Type, call the appropriate + // set routine + + switch (sqlType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + if(x.hasValue()) + { + OUString sStr; + x >>= sStr; + setParameter(parameterIndex, sqlType, scale, sStr); + } + else + setNull(parameterIndex,sqlType); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + if(x.hasValue()) + { + ORowSetValue aValue; + aValue.fill(x); + // TODO: make sure that this calls the string overload + setParameter(parameterIndex, sqlType, scale, aValue); + } + else + setNull(parameterIndex,sqlType); + break; + default: + ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); + } +} + + +void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ ) +{ + setNull(parameterIndex,sqlType); +} + + +void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) +{ + if (!::dbtools::implSetObject(this, parameterIndex, x)) + { // there is no other setXXX call which can handle the value in x + throw SQLException(); + } +} + + +void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) +{ + setScalarParameter(parameterIndex, DataType::SMALLINT, 5, 0, x); +} + + +void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) +{ + setParameter(parameterIndex, DataType::BINARY, x); +} + + +void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + // LEM: It is quite unclear to me what the interface here is. + // The XInputStream provides *bytes*, not characters. + setStream(parameterIndex, x, length, DataType::LONGVARCHAR); +} + + +void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + setStream(parameterIndex, x, length, DataType::LONGVARBINARY); +} + + +void SAL_CALL OPreparedStatement::clearParameters( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + prepareStatement(); + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + N3SQLFreeStmt (m_aStatementHandle, SQL_RESET_PARAMS); + N3SQLFreeStmt (m_aStatementHandle, SQL_UNBIND); +} + +void SAL_CALL OPreparedStatement::clearBatch( ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::clearBatch", *this ); + // clearParameters( ); + // m_aBatchVector.erase(); +} + + +void SAL_CALL OPreparedStatement::addBatch( ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::addBatch", *this ); +} + + +Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch( ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::executeBatch", *this ); + // not reached, but keep -Werror happy + return Sequence< sal_Int32 > (); +} + + +// methods + + +// initBoundParam +// Initialize the bound parameter objects + + +void OPreparedStatement::initBoundParam () +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + // Get the number of parameters + numParams = 0; + N3SQLNumParams (m_aStatementHandle,&numParams); + + // There are parameter markers, allocate the bound + // parameter objects + + if (numParams > 0) + { + boundParams.reset(new OBoundParam[numParams]); + } +} + + +// allocBindBuf +// Allocate storage for the permanent data buffer for the bound +// parameter. + + +void* OPreparedStatement::allocBindBuf( sal_Int32 index,sal_Int32 bufLen) +{ + void* b = nullptr; + + // Sanity check the parameter number + + if ((index >= 1) && (index <= numParams)) + { + b = boundParams[index - 1].allocBindDataBuffer(bufLen); + } + + return b; +} + + +// getLengthBuf +// Gets the length buffer for the given parameter index + + +SQLLEN* OPreparedStatement::getLengthBuf (sal_Int32 index) +{ + SQLLEN* b = nullptr; + + // Sanity check the parameter number + + if ((index >= 1) && + (index <= numParams)) + { + b = &boundParams[index - 1].getBindLengthBuffer (); + } + + return b; +} + + +// putParamData +// Puts parameter data from a previously bound input stream. The +// input stream was bound using SQL_LEN_DATA_AT_EXEC. +void OPreparedStatement::putParamData (sal_Int32 index) +{ + // Sanity check the parameter index + if ((index < 1) || + (index > numParams)) + { + return; + } + + // We'll transfer up to MAX_PUT_DATA_LENGTH at a time + Sequence< sal_Int8 > buf( MAX_PUT_DATA_LENGTH ); + + // Get the information about the input stream + + Reference< XInputStream> inputStream = boundParams[index - 1].getInputStream (); + if ( !inputStream.is() ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_NO_INPUTSTREAM)); + throw SQLException (sError, *this,OUString(),0,Any()); + } + + sal_Int32 maxBytesLeft = boundParams[index - 1].getInputStreamLen (); + + // Loop while more data from the input stream + sal_Int32 haveRead = 0; + try + { + + do + { + sal_Int32 toReadThisRound = std::min( MAX_PUT_DATA_LENGTH, maxBytesLeft ); + + // Read some data from the input stream + haveRead = inputStream->readBytes( buf, toReadThisRound ); + OSL_ENSURE( haveRead == buf.getLength(), "OPreparedStatement::putParamData: inconsistency!" ); + + if ( !haveRead ) + // no more data in the stream - the given stream length was a maximum which could not be + // fulfilled by the stream + break; + + // Put the data + OSL_ENSURE( m_aStatementHandle, "OPreparedStatement::putParamData: StatementHandle is null!" ); + N3SQLPutData ( m_aStatementHandle, buf.getArray(), buf.getLength() ); + + // decrement the number of bytes still needed + maxBytesLeft -= haveRead; + } + while ( maxBytesLeft > 0 ); + } + catch (const IOException& ex) + { + + // If an I/O exception was generated, turn + // it into a SQLException + + throw SQLException(ex.Message,*this,OUString(),0,Any()); + } +} + +// setStream +// Sets an input stream as a parameter, using the given SQL type +void OPreparedStatement::setStream( + sal_Int32 ParameterIndex, + const Reference< XInputStream>& x, + SQLLEN length, + sal_Int32 _nType) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + prepareStatement(); + + checkParameterIndex(ParameterIndex); + // Get the buffer needed for the length + + SQLLEN * const lenBuf = getLengthBuf(ParameterIndex); + + // Allocate a new buffer for the parameter data. This buffer + // will be returned by SQLParamData (it is set to the parameter + // number, a sal_Int32) + + sal_Int32* dataBuf = static_cast<sal_Int32*>( allocBindBuf(ParameterIndex, sizeof(ParameterIndex)) ); + *dataBuf = ParameterIndex; + + // Bind the parameter with SQL_LEN_DATA_AT_EXEC + *lenBuf = SQL_LEN_DATA_AT_EXEC (length); + + SQLSMALLINT fCType, fSqlType; + OTools::getBindTypes(bUseWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType); + + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + N3SQLBindParameter(m_aStatementHandle, + static_cast<SQLUSMALLINT>(ParameterIndex), + SQL_PARAM_INPUT, + fCType, + fSqlType, + length, + invalid_scale, + dataBuf, + sizeof(ParameterIndex), + lenBuf); + + // Save the input stream + boundParams[ParameterIndex - 1].setInputStream (x, length); +} + + +void OPreparedStatement::FreeParams() +{ + numParams = 0; + boundParams.reset(); +} + +void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + try + { + switch(nHandle) + { + case PROPERTY_ID_RESULTSETCONCURRENCY: + if(!isPrepared()) + setResultSetConcurrency(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_RESULTSETTYPE: + if(!isPrepared()) + setResultSetType(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHDIRECTION: + if(!isPrepared()) + setFetchDirection(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_USEBOOKMARKS: + if(!isPrepared()) + setUsingBookmarks(comphelper::getBOOL(rValue)); + break; + default: + OStatement_Base::setFastPropertyValue_NoBroadcast(nHandle,rValue); + } + } + catch(const SQLException&) + { + // throw Exception(e.Message,*this); + } +} + +void OPreparedStatement::prepareStatement() +{ + if(!isPrepared()) + { + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + OString aSql(OUStringToOString(m_sSqlStatement,getOwnConnection()->getTextEncoding())); + SQLRETURN nReturn = N3SQLPrepare(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())), aSql.getLength()); + OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this); + m_bPrepared = true; + initBoundParam(); + } +} + +void OPreparedStatement::checkParameterIndex(sal_Int32 _parameterIndex) +{ + if( _parameterIndex > numParams || + _parameterIndex < 1 || + _parameterIndex > std::numeric_limits<SQLUSMALLINT>::max() ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution(STR_WRONG_PARAM_INDEX, + "$pos$", OUString::number(_parameterIndex), + "$count$", OUString::number(numParams) + )); + SQLException aNext(sError,*this, OUString(),0,Any()); + + ::dbtools::throwInvalidIndexException(*this,makeAny(aNext)); + } +} + +OResultSet* OPreparedStatement::createResulSet() +{ + OResultSet* pReturn = new OResultSet(m_aStatementHandle,this); + pReturn->setMetaData(getMetaData()); + return pReturn; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/ORealDriver.cxx b/connectivity/source/drivers/odbc/ORealDriver.cxx new file mode 100644 index 000000000..47576954a --- /dev/null +++ b/connectivity/source/drivers/odbc/ORealDriver.cxx @@ -0,0 +1,292 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ORealDriver.hxx" +#include <odbc/ODriver.hxx> +#include <odbc/OTools.hxx> +#include <odbc/OFunctions.hxx> + +namespace connectivity::odbc +{ + namespace { + + class ORealOdbcDriver : public ODBCDriver + { + protected: + virtual oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const override; + virtual SQLHANDLE EnvironmentHandle(OUString &_rPath) override; + public: + explicit ORealOdbcDriver(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory) : ODBCDriver(_rxFactory) {} + }; + + } + +oslGenericFunction ORealOdbcDriver::getOdbcFunction(ODBC3SQLFunctionId _nIndex) const +{ + oslGenericFunction pFunction = nullptr; + switch(_nIndex) + { + case ODBC3SQLFunctionId::AllocHandle: + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLAllocHandle); + break; + case ODBC3SQLFunctionId::Connect: + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLConnect); + break; + case ODBC3SQLFunctionId::DriverConnect: + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDriverConnect); + break; + case ODBC3SQLFunctionId::BrowseConnect: + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLBrowseConnect); + break; + case ODBC3SQLFunctionId::DataSources: + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDataSources); + break; + case ODBC3SQLFunctionId::Drivers: + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDrivers); + break; + case ODBC3SQLFunctionId::GetInfo: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetInfo); + break; + case ODBC3SQLFunctionId::GetFunctions: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetFunctions); + break; + case ODBC3SQLFunctionId::GetTypeInfo: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetTypeInfo); + break; + case ODBC3SQLFunctionId::SetConnectAttr: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetConnectAttr); + break; + case ODBC3SQLFunctionId::GetConnectAttr: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetConnectAttr); + break; + case ODBC3SQLFunctionId::SetEnvAttr: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetEnvAttr); + break; + case ODBC3SQLFunctionId::GetEnvAttr: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetEnvAttr); + break; + case ODBC3SQLFunctionId::SetStmtAttr: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetStmtAttr); + break; + case ODBC3SQLFunctionId::GetStmtAttr: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetStmtAttr); + break; + case ODBC3SQLFunctionId::Prepare: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLPrepare); + break; + case ODBC3SQLFunctionId::BindParameter: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLBindParameter); + break; + case ODBC3SQLFunctionId::SetCursorName: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetCursorName); + break; + case ODBC3SQLFunctionId::Execute: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLExecute); + break; + case ODBC3SQLFunctionId::ExecDirect: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLExecDirect); + break; + case ODBC3SQLFunctionId::DescribeParam: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDescribeParam); + break; + case ODBC3SQLFunctionId::NumParams: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLNumParams); + break; + case ODBC3SQLFunctionId::ParamData: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLParamData); + break; + case ODBC3SQLFunctionId::PutData: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLPutData); + break; + case ODBC3SQLFunctionId::RowCount: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLRowCount); + break; + case ODBC3SQLFunctionId::NumResultCols: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLNumResultCols); + break; + case ODBC3SQLFunctionId::DescribeCol: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDescribeCol); + break; + case ODBC3SQLFunctionId::ColAttribute: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLColAttribute); + break; + case ODBC3SQLFunctionId::BindCol: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLBindCol); + break; + case ODBC3SQLFunctionId::Fetch: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLFetch); + break; + case ODBC3SQLFunctionId::FetchScroll: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLFetchScroll); + break; + case ODBC3SQLFunctionId::GetData: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetData); + break; + case ODBC3SQLFunctionId::SetPos: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSetPos); + break; + case ODBC3SQLFunctionId::BulkOperations: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLBulkOperations); + break; + case ODBC3SQLFunctionId::MoreResults: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLMoreResults); + break; + case ODBC3SQLFunctionId::GetDiagRec: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetDiagRec); + break; + case ODBC3SQLFunctionId::ColumnPrivileges: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLColumnPrivileges); + break; + case ODBC3SQLFunctionId::Columns: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLColumns); + break; + case ODBC3SQLFunctionId::ForeignKeys: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLForeignKeys); + break; + case ODBC3SQLFunctionId::PrimaryKeys: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLPrimaryKeys); + break; + case ODBC3SQLFunctionId::ProcedureColumns: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLProcedureColumns); + break; + case ODBC3SQLFunctionId::Procedures: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLProcedures); + break; + case ODBC3SQLFunctionId::SpecialColumns: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLSpecialColumns); + break; + case ODBC3SQLFunctionId::Statistics: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLStatistics); + break; + case ODBC3SQLFunctionId::TablePrivileges: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLTablePrivileges); + break; + case ODBC3SQLFunctionId::Tables: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLTables); + break; + case ODBC3SQLFunctionId::FreeStmt: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLFreeStmt); + break; + case ODBC3SQLFunctionId::CloseCursor: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLCloseCursor); + break; + case ODBC3SQLFunctionId::Cancel: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLCancel); + break; + case ODBC3SQLFunctionId::EndTran: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLEndTran); + break; + case ODBC3SQLFunctionId::Disconnect: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLDisconnect); + break; + case ODBC3SQLFunctionId::FreeHandle: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLFreeHandle); + break; + case ODBC3SQLFunctionId::GetCursorName: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLGetCursorName); + break; + case ODBC3SQLFunctionId::NativeSql: + + pFunction = reinterpret_cast<oslGenericFunction>(pODBC3SQLNativeSql); + break; + default: + OSL_FAIL("Function unknown!"); + } + return pFunction; +} + + +css::uno::Reference< css::uno::XInterface > ODBCDriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory) +{ + return *(new ORealOdbcDriver(_rxFactory)); +} + +// ODBC Environment (common for all Connections): +SQLHANDLE ORealOdbcDriver::EnvironmentHandle(OUString &_rPath) +{ + // Is (for this instance) already an Environment made? + if (!m_pDriverHandle) + { + SQLHANDLE h = SQL_NULL_HANDLE; + // allocate Environment + + // load ODBC-DLL now: + if (!LoadLibrary_ODBC3(_rPath) || N3SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&h) != SQL_SUCCESS) + return SQL_NULL_HANDLE; + + // Save in global Structure + m_pDriverHandle = h; + N3SQLSetEnvAttr(h, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3), SQL_IS_UINTEGER); + //N3SQLSetEnvAttr(h, SQL_ATTR_CONNECTION_POOLING,(SQLPOINTER) SQL_CP_ONE_PER_HENV, SQL_IS_INTEGER); + } + + return m_pDriverHandle; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/ORealDriver.hxx b/connectivity/source/drivers/odbc/ORealDriver.hxx new file mode 100644 index 000000000..cfecb3893 --- /dev/null +++ b/connectivity/source/drivers/odbc/ORealDriver.hxx @@ -0,0 +1,42 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_ODBC_OREALDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_ODBC_OREALDRIVER_HXX + +#include <sal/config.h> + +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star { + namespace lang { class XMultiServiceFactory; } + namespace uno { class XInterface; } +} + +namespace connectivity::odbc { + +/// @throws css::uno::Exception +css::uno::Reference< css::uno::XInterface > +ODBCDriver_CreateInstance( css::uno::Reference< css::lang::XMultiServiceFactory > const & factory); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/OResultSet.cxx b/connectivity/source/drivers/odbc/OResultSet.cxx new file mode 100644 index 000000000..61e5caecf --- /dev/null +++ b/connectivity/source/drivers/odbc/OResultSet.cxx @@ -0,0 +1,1803 @@ +/* -*- 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 <odbc/OResultSet.hxx> +#include <odbc/OTools.hxx> +#include <odbc/OResultSetMetaData.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyVetoException.hpp> +#include <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <comphelper/property.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <o3tl/safeint.hxx> +#include <sal/log.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::odbc; +using namespace cppu; +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +#define ODBC_SQL_NOT_DEFINED 99UL +static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_OFF, "ODBC_SQL_NOT_DEFINED must be unique"); +static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_ON, "ODBC_SQL_NOT_DEFINED must be unique"); +static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_FIXED, "ODBC_SQL_NOT_DEFINED must be unique"); +static_assert(ODBC_SQL_NOT_DEFINED != SQL_UB_VARIABLE, "ODBC_SQL_NOT_DEFINED must be unique"); + +namespace +{ + const SQLLEN nMaxBookmarkLen = 20; +} + + +// IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.OResultSet","com.sun.star.sdbc.ResultSet"); +OUString SAL_CALL OResultSet::getImplementationName( ) +{ + return "com.sun.star.sdbcx.odbc.ResultSet"; +} + + Sequence< OUString > SAL_CALL OResultSet::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL OResultSet::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +OResultSet::OResultSet(SQLHANDLE _pStatementHandle ,OStatement_Base* pStmt) : OResultSet_BASE(m_aMutex) + ,OPropertySetHelper(OResultSet_BASE::rBHelper) + ,m_bFetchDataInOrder(true) + ,m_aStatementHandle(_pStatementHandle) + ,m_aConnectionHandle(pStmt->getConnectionHandle()) + ,m_pStatement(pStmt) + ,m_xStatement(*pStmt) + ,m_nTextEncoding(pStmt->getOwnConnection()->getTextEncoding()) + ,m_nRowPos(0) + ,m_nUseBookmarks(ODBC_SQL_NOT_DEFINED) + ,m_nCurrentFetchState(0) + ,m_bWasNull(true) + ,m_bEOF(true) + ,m_bRowInserted(false) + ,m_bRowDeleted(false) + ,m_bUseFetchScroll(false) +{ + osl_atomic_increment( &m_refCount ); + try + { + m_pRowStatusArray.reset( new SQLUSMALLINT[1] ); // the default value + setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray.get()); + } + catch(const Exception&) + { // we don't want our result destroy here + } + SQLULEN nCurType = 0; + try + { + nCurType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE); + SQLUINTEGER nValueLen = m_pStatement->getCursorProperties(nCurType,false); + if( (nValueLen & SQL_CA2_SENSITIVITY_DELETIONS) != SQL_CA2_SENSITIVITY_DELETIONS || + (nValueLen & SQL_CA2_CRC_EXACT) != SQL_CA2_CRC_EXACT) + m_pSkipDeletedSet.reset( new OSkipDeletedSet(this) ); + } + catch(const Exception&) + { // we don't want our result destroy here + } + try + { + SQLUINTEGER nValueLen = 0; + // Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441%28v=vs.85%29.aspx + // LibreOffice ODBC binds columns only on update, so we don't care about SQL_GD_ANY_COLUMN / SQL_GD_BOUND + // TODO: maybe a problem if a column is updated, then an earlier column fetched? + // an updated column is bound... + // TODO: aren't we assuming SQL_GD_OUTPUT_PARAMS? + // If yes, we should at least OSL_ENSURE it, + // even better throw an exception any OUT parameter registration if !SQL_GD_OUTPUT_PARAMS. + // If !SQL_GD_ANY_ORDER, cache the whole row so that callers can access columns in any order. + // In other words, isolate them from ODBC restrictions. + // TODO: we assume SQL_GD_BLOCK, unless fetchSize is 1 + OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_GETDATA_EXTENSIONS,nValueLen,nullptr); + m_bFetchDataInOrder = ((SQL_GD_ANY_ORDER & nValueLen) != SQL_GD_ANY_ORDER); + } + catch(const Exception&) + { + m_bFetchDataInOrder = true; + } + try + { + // TODO: this does *not* do what it appears. + // We use SQLFetchScroll unconditionally in several places + // the *only* difference this makes is whether ::next() uses SQLFetchScroll or SQLFetch + // so this test seems pointless + if ( getOdbcFunction(ODBC3SQLFunctionId::GetFunctions) ) + { + SQLUSMALLINT nSupported = 0; + m_bUseFetchScroll = ( N3SQLGetFunctions(m_aConnectionHandle,SQL_API_SQLFETCHSCROLL,&nSupported) == SQL_SUCCESS && nSupported == 1 ); + } + } + catch(const Exception&) + { + m_bUseFetchScroll = false; + } + + osl_atomic_decrement( &m_refCount ); +} + +OResultSet::~OResultSet() +{ +} + +void OResultSet::construct() +{ + osl_atomic_increment( &m_refCount ); + allocBuffer(); + osl_atomic_decrement( &m_refCount ); +} + +void OResultSet::disposing() +{ + N3SQLCloseCursor(m_aStatementHandle); + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + releaseBuffer(); + + setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, nullptr); + m_xStatement.clear(); + m_xMetaData.clear(); +} + +SQLRETURN OResultSet::unbind(bool _bUnbindHandle) +{ + SQLRETURN nRet = 0; + if ( _bUnbindHandle ) + nRet = N3SQLFreeStmt(m_aStatementHandle,SQL_UNBIND); + + if ( !m_aBindVector.empty() ) + { + for(auto& [rPtrAddr, rType] : m_aBindVector) + { + switch (rType) + { + case DataType::CHAR: + case DataType::VARCHAR: + delete static_cast< OString* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::BIGINT: + delete static_cast< sal_Int64* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + delete static_cast< OString* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::REAL: + case DataType::DOUBLE: + delete static_cast< double* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::LONGVARCHAR: + case DataType::CLOB: + delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::LONGVARBINARY: + case DataType::BLOB: + delete [] static_cast< char* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::DATE: + delete static_cast< DATE_STRUCT* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::TIME: + delete static_cast< TIME_STRUCT* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::TIMESTAMP: + delete static_cast< TIMESTAMP_STRUCT* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::BIT: + case DataType::TINYINT: + delete static_cast< sal_Int8* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::SMALLINT: + delete static_cast< sal_Int16* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::INTEGER: + delete static_cast< sal_Int32* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::FLOAT: + delete static_cast< float* >(reinterpret_cast< void * >(rPtrAddr)); + break; + case DataType::BINARY: + case DataType::VARBINARY: + delete static_cast< sal_Int8* >(reinterpret_cast< void * >(rPtrAddr)); + break; + } + } + m_aBindVector.clear(); + } + return nRet; +} + +TVoidPtr OResultSet::allocBindColumn(sal_Int32 _nType,sal_Int32 _nColumnIndex) +{ + TVoidPtr aPair; + switch (_nType) + { + case DataType::CHAR: + case DataType::VARCHAR: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new OString()),_nType); + break; + case DataType::BIGINT: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int64(0)),_nType); + break; + case DataType::DECIMAL: + case DataType::NUMERIC: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new OString()),_nType); + break; + case DataType::REAL: + case DataType::DOUBLE: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new double(0.0)),_nType); + break; + case DataType::LONGVARCHAR: + case DataType::CLOB: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new char[2]),_nType); // only for finding + break; + case DataType::LONGVARBINARY: + case DataType::BLOB: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new char[2]),_nType); // only for finding + break; + case DataType::DATE: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new DATE_STRUCT),_nType); + break; + case DataType::TIME: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new TIME_STRUCT),_nType); + break; + case DataType::TIMESTAMP: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new TIMESTAMP_STRUCT),_nType); + break; + case DataType::BIT: + case DataType::TINYINT: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int8(0)),_nType); + break; + case DataType::SMALLINT: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int16(0)),_nType); + break; + case DataType::INTEGER: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int32(0)),_nType); + break; + case DataType::FLOAT: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new float(0)),_nType); + break; + case DataType::BINARY: + case DataType::VARBINARY: + aPair = TVoidPtr(reinterpret_cast< sal_Int64 >(new sal_Int8[m_aRow[_nColumnIndex].getSequence().getLength()]),_nType); + break; + default: + SAL_WARN( "connectivity.odbc", "Unknown type"); + aPair = TVoidPtr(0,_nType); + } + return aPair; +} + +void OResultSet::allocBuffer() +{ + Reference< XResultSetMetaData > xMeta = getMetaData(); + sal_Int32 nLen = xMeta->getColumnCount(); + + m_aBindVector.reserve(nLen); + m_aRow.resize(nLen+1); + + m_aRow[0].setTypeKind(DataType::VARBINARY); + m_aRow[0].setBound( false ); + + for(sal_Int32 i = 1;i<=nLen;++i) + { + sal_Int32 nType = xMeta->getColumnType(i); + m_aRow[i].setTypeKind( nType ); + m_aRow[i].setBound( false ); + } + m_aLengthVector.resize(nLen + 1); +} + +void OResultSet::releaseBuffer() +{ + unbind(false); + m_aLengthVector.clear(); +} + +Any SAL_CALL OResultSet::queryInterface( const Type & rType ) +{ + Any aRet = OPropertySetHelper::queryInterface(rType); + return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType); +} + + Sequence< Type > SAL_CALL OResultSet::getTypes( ) +{ + 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(),OResultSet_BASE::getTypes()); +} + + +sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName ) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + ::osl::MutexGuard aGuard( m_aMutex ); + + 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 ); + assert(false); + return 0; // Never reached +} + +void OResultSet::ensureCacheForColumn(sal_Int32 columnIndex) +{ + SAL_INFO( "connectivity.odbc", "odbc lionel@mamane.lu OResultSet::ensureCacheForColumn" ); + + assert(columnIndex >= 0); + + const TDataRow::size_type oldCacheSize = m_aRow.size(); + const TDataRow::size_type uColumnIndex = static_cast<TDataRow::size_type>(columnIndex); + + if (oldCacheSize > uColumnIndex) + // nothing to do + return; + + m_aRow.resize(columnIndex + 1); + TDataRow::iterator i (m_aRow.begin() + oldCacheSize); + const TDataRow::const_iterator end(m_aRow.end()); + for (; i != end; ++i) + { + i->setBound(false); + } +} +void OResultSet::invalidateCache() +{ + for(auto& rItem : m_aRow) + { + rItem.setBound(false); + } +} + +Reference< XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this ); + + return nullptr; +} + +Reference< XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBinaryStream", *this ); + + return nullptr; +} + +template < typename T > T OResultSet::impl_getValue( const sal_Int32 _nColumnIndex, SQLSMALLINT nType ) +{ + T val; + + OTools::getValue(m_pStatement->getOwnConnection(), m_aStatementHandle, _nColumnIndex, nType, m_bWasNull, **this, &val, sizeof(val)); + + return val; +} + +// this function exists for the implicit conversion to sal_Bool (compared to a direct call to impl_getValue) +bool OResultSet::impl_getBoolean( sal_Int32 columnIndex ) +{ + return impl_getValue<sal_Int8>(columnIndex, SQL_C_BIT); +} + +template < typename T > T OResultSet::getValue( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + fillColumn(columnIndex); + m_bWasNull = m_aRow[columnIndex].isNull(); + return m_aRow[columnIndex]; +} +sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 columnIndex ) +{ + return getValue<bool>( columnIndex ); +} + +sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 columnIndex ) +{ + return getValue<sal_Int8>( columnIndex ); +} + + +Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + fillColumn(columnIndex); + m_bWasNull = m_aRow[columnIndex].isNull(); + + Sequence< sal_Int8 > nRet; + switch(m_aRow[columnIndex].getTypeKind()) + { + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + nRet = m_aRow[columnIndex]; + break; + default: + { + OUString const & sRet = m_aRow[columnIndex].getString(); + nRet = Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(sRet.getStr()),sizeof(sal_Unicode)*sRet.getLength()); + } + } + return nRet; +} +Sequence< sal_Int8 > OResultSet::impl_getBytes( sal_Int32 columnIndex ) +{ + const SWORD nColumnType = impl_getColumnType_nothrow(columnIndex); + + switch(nColumnType) + { + case SQL_WVARCHAR: + case SQL_WCHAR: + case SQL_WLONGVARCHAR: + case SQL_VARCHAR: + case SQL_CHAR: + case SQL_LONGVARCHAR: + { + OUString const & aRet = OTools::getStringValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,nColumnType,m_bWasNull,**this,m_nTextEncoding); + return Sequence<sal_Int8>(reinterpret_cast<const sal_Int8*>(aRet.getStr()),sizeof(sal_Unicode)*aRet.getLength()); + } + default: + return OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,SQL_C_BINARY,m_bWasNull,**this); + } +} + +Date OResultSet::impl_getDate( sal_Int32 columnIndex ) +{ + DATE_STRUCT aDate = impl_getValue< DATE_STRUCT> ( columnIndex, + m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_DATE : SQL_C_TYPE_DATE ); + + return Date(aDate.day, aDate.month, aDate.year); +} + +Date SAL_CALL OResultSet::getDate( sal_Int32 columnIndex ) +{ + return getValue<Date>( columnIndex ); +} + + +double SAL_CALL OResultSet::getDouble( sal_Int32 columnIndex ) +{ + return getValue<double>( columnIndex ); +} + + +float SAL_CALL OResultSet::getFloat( sal_Int32 columnIndex ) +{ + return getValue<float>( columnIndex ); +} + +sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 columnIndex ) +{ + return getValue<sal_Int16>( columnIndex ); +} + +sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 columnIndex ) +{ + return getValue<sal_Int32>( columnIndex ); +} + +sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 columnIndex ) +{ + return getValue<sal_Int64>( columnIndex ); +} +sal_Int64 OResultSet::impl_getLong( sal_Int32 columnIndex ) +{ + try + { + return impl_getValue<sal_Int64>(columnIndex, SQL_C_SBIGINT); + } + catch(const SQLException&) + { + return getString(columnIndex).toInt64(); + } +} + +sal_Int32 SAL_CALL OResultSet::getRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_pSkipDeletedSet ? m_pSkipDeletedSet->getMappedPosition(getDriverPos()) : getDriverPos(); +} + +Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(m_pStatement->getOwnConnection(),m_aStatementHandle); + return m_xMetaData; +} + +Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getArray", *this ); + return nullptr; +} + + +Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getClob", *this ); + return nullptr; +} + +Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getBlob", *this ); + return nullptr; +} + + +Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRow::getRef", *this ); + return nullptr; +} + + +Any SAL_CALL OResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ ) +{ + return getValue<ORowSetValue>( columnIndex ).makeAny(); +} + +OUString OResultSet::impl_getString( sal_Int32 columnIndex ) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + const SWORD nColumnType = impl_getColumnType_nothrow(columnIndex); + return OTools::getStringValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,nColumnType,m_bWasNull,**this,m_nTextEncoding); +} +OUString OResultSet::getString( sal_Int32 columnIndex ) +{ + return getValue<OUString>( columnIndex ); +} + +Time OResultSet::impl_getTime( sal_Int32 columnIndex ) +{ + TIME_STRUCT aTime = impl_getValue< TIME_STRUCT > ( columnIndex, + m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_TIME : SQL_C_TYPE_TIME ); + + return Time(0, aTime.second,aTime.minute,aTime.hour, false); +} +Time SAL_CALL OResultSet::getTime( sal_Int32 columnIndex ) +{ + return getValue<Time>( columnIndex ); +} + +DateTime OResultSet::impl_getTimestamp( sal_Int32 columnIndex ) +{ + TIMESTAMP_STRUCT aTime = impl_getValue< TIMESTAMP_STRUCT > ( columnIndex, + m_pStatement->getOwnConnection()->useOldDateFormat() ? SQL_C_TIMESTAMP : SQL_C_TYPE_TIMESTAMP ); + + return DateTime(aTime.fraction, + aTime.second, + aTime.minute, + aTime.hour, + aTime.day, + aTime.month, + aTime.year, + false); +} +DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + return getValue<DateTime>( columnIndex ); +} + +sal_Bool SAL_CALL OResultSet::isBeforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_nRowPos == 0; +} + +sal_Bool SAL_CALL OResultSet::isAfterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nRowPos != 0 && m_nCurrentFetchState == SQL_NO_DATA; +} + +sal_Bool SAL_CALL OResultSet::isFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_nRowPos == 1; +} + +sal_Bool SAL_CALL OResultSet::isLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_bEOF && m_nCurrentFetchState != SQL_NO_DATA; +} + +void SAL_CALL OResultSet::beforeFirst( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + if(first()) + previous(); + m_nCurrentFetchState = SQL_SUCCESS; +} + +void SAL_CALL OResultSet::afterLast( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + if(last()) + next(); + m_bEOF = true; +} + + +void SAL_CALL OResultSet::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + } + dispose(); +} + + +sal_Bool SAL_CALL OResultSet::first( ) +{ + return moveImpl(IResultSetHelper::FIRST,0); +} + + +sal_Bool SAL_CALL OResultSet::last( ) +{ + return moveImpl(IResultSetHelper::LAST,0); +} + +sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row ) +{ + return moveImpl(IResultSetHelper::ABSOLUTE1,row); +} + +sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row ) +{ + return moveImpl(IResultSetHelper::RELATIVE1,row); +} + +sal_Bool SAL_CALL OResultSet::previous( ) +{ + return moveImpl(IResultSetHelper::PRIOR,0); +} + +Reference< XInterface > SAL_CALL OResultSet::getStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return m_xStatement; +} + + +sal_Bool SAL_CALL OResultSet::rowDeleted() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + bool bRet = m_bRowDeleted; + m_bRowDeleted = false; + + return bRet; +} + +sal_Bool SAL_CALL OResultSet::rowInserted( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + bool bInserted = m_bRowInserted; + m_bRowInserted = false; + + return bInserted; +} + +sal_Bool SAL_CALL OResultSet::rowUpdated( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + return m_pRowStatusArray[0] == SQL_ROW_UPDATED; +} + + +sal_Bool SAL_CALL OResultSet::next( ) +{ + return moveImpl(IResultSetHelper::NEXT,1); +} + + +sal_Bool SAL_CALL OResultSet::wasNull( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return m_bWasNull; +} + + +void SAL_CALL OResultSet::cancel( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + N3SQLCancel(m_aStatementHandle); +} + +void SAL_CALL OResultSet::clearWarnings( ) +{ +} + +Any SAL_CALL OResultSet::getWarnings( ) +{ + return Any(); +} + +void SAL_CALL OResultSet::insertRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + SQLLEN nRealLen = 0; + Sequence<sal_Int8> aBookmark(nMaxBookmarkLen); + static_assert(o3tl::make_unsigned(nMaxBookmarkLen) >= sizeof(SQLLEN), "must be larger"); + + SQLRETURN nRet = N3SQLBindCol(m_aStatementHandle, + 0, + SQL_C_VARBOOKMARK, + aBookmark.getArray(), + nMaxBookmarkLen, + &nRealLen + ); + + bool bPositionByBookmark = ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations ) ); + if ( bPositionByBookmark ) + { + nRet = N3SQLBulkOperations( m_aStatementHandle, SQL_ADD ); + fillNeededData( nRet ); + } + else + { + if(isBeforeFirst()) + next(); // must be done + nRet = N3SQLSetPos( m_aStatementHandle, 1, SQL_ADD, SQL_LOCK_NO_CHANGE ); + fillNeededData( nRet ); + } + aBookmark.realloc(nRealLen); + try + { + OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + } + catch(const SQLException&) + { + nRet = unbind(); + throw; + } + + nRet = unbind(); + OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + + if ( bPositionByBookmark ) + { + setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray())); + + nRet = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,0); + } + else + nRet = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_RELATIVE,0); // OJ 06.03.2004 + // sometimes we got an error but we are not interested in anymore #106047# OJ + // OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + + if(m_pSkipDeletedSet) + { + if(moveToBookmark(makeAny(aBookmark))) + { + sal_Int32 nRowPos = getDriverPos(); + if ( -1 == m_nRowPos ) + { + nRowPos = m_aPosToBookmarks.size() + 1; + } + if ( nRowPos == m_nRowPos ) + ++nRowPos; + m_nRowPos = nRowPos; + m_pSkipDeletedSet->insertNewPosition(nRowPos); + m_aPosToBookmarks[aBookmark] = nRowPos; + } + } + m_bRowInserted = true; + +} + +void SAL_CALL OResultSet::updateRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + SQLRETURN nRet; + + try + { + bool bPositionByBookmark = ( nullptr != getOdbcFunction( ODBC3SQLFunctionId::BulkOperations ) ); + if ( bPositionByBookmark ) + { + getBookmark(); + assert(m_aRow[0].isBound()); + Sequence<sal_Int8> aBookmark(m_aRow[0].getSequence()); + SQLLEN nRealLen = aBookmark.getLength(); + nRet = N3SQLBindCol(m_aStatementHandle, + 0, + SQL_C_VARBOOKMARK, + aBookmark.getArray(), + aBookmark.getLength(), + &nRealLen + ); + OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + nRet = N3SQLBulkOperations(m_aStatementHandle, SQL_UPDATE_BY_BOOKMARK); + fillNeededData(nRet); + // the driver should not have touched this + // (neither the contents of aBookmark FWIW) + assert(nRealLen == aBookmark.getLength()); + } + else + { + nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_UPDATE,SQL_LOCK_NO_CHANGE); + fillNeededData(nRet); + } + OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + // unbind all columns so we can fetch all columns again with SQLGetData + // (and also so that our buffers don't clobber anything, and + // so that a subsequent fetch does not overwrite m_aRow[0]) + invalidateCache(); + nRet = unbind(); + OSL_ENSURE(nRet == SQL_SUCCESS,"ODBC insert could not unbind the columns after success"); + } + catch(...) + { + // unbind all columns so that a subsequent fetch does not overwrite m_aRow[0] + nRet = unbind(); + OSL_ENSURE(nRet == SQL_SUCCESS,"ODBC insert could not unbind the columns after failure"); + throw; + } +} + +void SAL_CALL OResultSet::deleteRow( ) +{ + SQLRETURN nRet = SQL_SUCCESS; + sal_Int32 nPos = getDriverPos(); + nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_DELETE,SQL_LOCK_NO_CHANGE); + OTools::ThrowException(m_pStatement->getOwnConnection(),nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + + m_bRowDeleted = ( m_pRowStatusArray[0] == SQL_ROW_DELETED ); + if ( m_bRowDeleted ) + { + TBookmarkPosMap::iterator aIter = std::find_if(m_aPosToBookmarks.begin(), m_aPosToBookmarks.end(), + [&nPos](const TBookmarkPosMap::value_type& rEntry) { return rEntry.second == nPos; }); + if (aIter != m_aPosToBookmarks.end()) + m_aPosToBookmarks.erase(aIter); + } + if ( m_pSkipDeletedSet ) + m_pSkipDeletedSet->deletePosition(nPos); +} + + +void SAL_CALL OResultSet::cancelRowUpdates( ) +{ +} + + +void SAL_CALL OResultSet::moveToInsertRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + invalidateCache(); + // first unbound all columns + OSL_VERIFY( unbind() == SQL_SUCCESS ); + // SQLRETURN nRet = N3SQLSetStmtAttr(m_aStatementHandle,SQL_ATTR_ROW_ARRAY_SIZE ,(SQLPOINTER)1,SQL_IS_INTEGER); +} + + +void SAL_CALL OResultSet::moveToCurrentRow( ) +{ + invalidateCache(); +} + +void OResultSet::updateValue(sal_Int32 columnIndex, SQLSMALLINT _nType, void const * _pValue) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_aBindVector.push_back(allocBindColumn(OTools::MapOdbcType2Jdbc(_nType),columnIndex)); + void* pData = reinterpret_cast<void*>(m_aBindVector.rbegin()->first); + OSL_ENSURE(pData != nullptr,"Data for update is NULL!"); + OTools::bindValue( m_pStatement->getOwnConnection(), + m_aStatementHandle, + columnIndex, + _nType, + 0, + _pValue, + pData, + &m_aLengthVector[columnIndex], + **this, + m_nTextEncoding, + m_pStatement->getOwnConnection()->useOldDateFormat()); +} + +void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_aBindVector.push_back(allocBindColumn(DataType::CHAR,columnIndex)); + void* pData = reinterpret_cast<void*>(m_aBindVector.rbegin()->first); + OTools::bindValue(m_pStatement->getOwnConnection(),m_aStatementHandle,columnIndex,SQL_CHAR,0,nullptr,pData,&m_aLengthVector[columnIndex],**this,m_nTextEncoding,m_pStatement->getOwnConnection()->useOldDateFormat()); +} + + +void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) +{ + updateValue(columnIndex,SQL_BIT,&x); +} + +void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x ) +{ + updateValue(columnIndex,SQL_CHAR,&x); +} + + +void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x ) +{ + updateValue(columnIndex,SQL_TINYINT,&x); +} + +void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x ) +{ + updateValue(columnIndex,SQL_INTEGER,&x); +} + +void SAL_CALL OResultSet::updateLong( sal_Int32 /*columnIndex*/, sal_Int64 /*x*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRowUpdate::updateLong", *this ); +} + +void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x ) +{ + updateValue(columnIndex,SQL_REAL,&x); +} + + +void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x ) +{ + updateValue(columnIndex,SQL_DOUBLE,&x); +} + +void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x ) +{ + sal_Int32 nType = m_aRow[columnIndex].getTypeKind(); + SQLSMALLINT nOdbcType = OTools::jdbcTypeToOdbc(nType); + m_aRow[columnIndex] = x; + m_aRow[columnIndex].setTypeKind(nType); // OJ: otherwise longvarchar will be recognized by fillNeededData + m_aRow[columnIndex].setBound(true); + updateValue(columnIndex,nOdbcType, &x); +} + +void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x ) +{ + sal_Int32 nType = m_aRow[columnIndex].getTypeKind(); + SQLSMALLINT nOdbcType = OTools::jdbcTypeToOdbc(nType); + m_aRow[columnIndex] = x; + m_aRow[columnIndex].setTypeKind(nType); // OJ: otherwise longvarbinary will be recognized by fillNeededData + m_aRow[columnIndex].setBound(true); + updateValue(columnIndex,nOdbcType, &x); +} + +void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const Date& x ) +{ + DATE_STRUCT aVal = OTools::DateToOdbcDate(x); + updateValue(columnIndex,SQL_DATE,&aVal); +} + + +void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x ) +{ + TIME_STRUCT aVal = OTools::TimeToOdbcTime(x); + updateValue(columnIndex,SQL_TIME,&aVal); +} + + +void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const DateTime& x ) +{ + TIMESTAMP_STRUCT aVal = OTools::DateTimeToTimestamp(x); + updateValue(columnIndex,SQL_TIMESTAMP,&aVal); +} + + +void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< XInputStream >& x, sal_Int32 length ) +{ + if(!x.is()) + ::dbtools::throwFunctionSequenceException(*this); + + Sequence<sal_Int8> aSeq; + x->readBytes(aSeq,length); + updateBytes(columnIndex,aSeq); +} + +void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< XInputStream >& x, sal_Int32 length ) +{ + updateBinaryStream(columnIndex,x,length); +} + +void SAL_CALL OResultSet::refreshRow( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + // SQLRETURN nRet = N3SQLSetPos(m_aStatementHandle,1,SQL_REFRESH,SQL_LOCK_NO_CHANGE); + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_RELATIVE,0); + OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); +} + +void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x ) +{ + if (!::dbtools::implUpdateObject(this, columnIndex, x)) + throw SQLException(); +} + + +void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ ) +{ + if (!::dbtools::implUpdateObject(this, columnIndex, x)) + throw SQLException(); +} + +// XRowLocate +Any SAL_CALL OResultSet::getBookmark( ) +{ + fillColumn(0); + if(m_aRow[0].isNull()) + throw SQLException(); + return m_aRow[0].makeAny(); +} +Sequence<sal_Int8> OResultSet::impl_getBookmark( ) +{ + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + TBookmarkPosMap::const_iterator aFind = std::find_if(m_aPosToBookmarks.begin(),m_aPosToBookmarks.end(), + [this] (const TBookmarkPosMap::value_type& bookmarkPos) { + return bookmarkPos.second == m_nRowPos; + }); + + if ( aFind == m_aPosToBookmarks.end() ) + { + if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED ) + { + m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS); + } + if(m_nUseBookmarks == SQL_UB_OFF) + throw SQLException(); + + Sequence<sal_Int8> bookmark = OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,0,SQL_C_VARBOOKMARK,m_bWasNull,**this); + m_aPosToBookmarks[bookmark] = m_nRowPos; + OSL_ENSURE(bookmark.hasElements(),"Invalid bookmark from length 0!"); + return bookmark; + } + else + { + return aFind->first; + } +} + +sal_Bool SAL_CALL OResultSet::moveToBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + invalidateCache(); + Sequence<sal_Int8> aBookmark; + bookmark >>= aBookmark; + OSL_ENSURE(aBookmark.hasElements(),"Invalid bookmark from length 0!"); + if(aBookmark.hasElements()) + { + SQLRETURN nReturn = setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray())); + + if ( SQL_INVALID_HANDLE != nReturn && SQL_ERROR != nReturn ) + { + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,0); + OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + TBookmarkPosMap::const_iterator aFind = m_aPosToBookmarks.find(aBookmark); + if(aFind != m_aPosToBookmarks.end()) + m_nRowPos = aFind->second; + else + m_nRowPos = -1; + return m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO; + } + } + return false; +} + +sal_Bool SAL_CALL OResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + invalidateCache(); + Sequence<sal_Int8> aBookmark; + bookmark >>= aBookmark; + setStmtOption<SQLLEN*, SQL_IS_POINTER>(SQL_ATTR_FETCH_BOOKMARK_PTR, reinterpret_cast<SQLLEN*>(aBookmark.getArray())); + + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,SQL_FETCH_BOOKMARK,rows); + OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + return m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO; +} + +sal_Int32 SAL_CALL OResultSet::compareBookmarks( const Any& lhs, const Any& rhs ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return (lhs == rhs) ? CompareBookmark::EQUAL : CompareBookmark::NOT_EQUAL; +} + +sal_Bool SAL_CALL OResultSet::hasOrderedBookmarks( ) +{ + return false; +} + +sal_Int32 SAL_CALL OResultSet::hashBookmark( const Any& /*bookmark*/ ) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "XRowLocate::hashBookmark", *this ); + return 0; +} + +// XDeleteRows +Sequence< sal_Int32 > SAL_CALL OResultSet::deleteRows( const Sequence< Any >& rows ) +{ + Sequence< sal_Int32 > aRet(rows.getLength()); + sal_Int32 *pRet = aRet.getArray(); + + const Any *pBegin = rows.getConstArray(); + const Any *pEnd = pBegin + rows.getLength(); + + for(;pBegin != pEnd;++pBegin,++pRet) + { + try + { + if(moveToBookmark(*pBegin)) + { + deleteRow(); + *pRet = 1; + } + } + catch(const SQLException&) + { + *pRet = 0; + } + } + return aRet; +} + +template < typename T, SQLINTEGER BufferLength > T OResultSet::getStmtOption (SQLINTEGER fOption) const +{ + T result (0); + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + N3SQLGetStmtAttr(m_aStatementHandle, fOption, &result, BufferLength, nullptr); + return result; +} +template < typename T, SQLINTEGER BufferLength > SQLRETURN OResultSet::setStmtOption (SQLINTEGER fOption, T value) const +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLPOINTER sv = reinterpret_cast<SQLPOINTER>(value); + return N3SQLSetStmtAttr(m_aStatementHandle, fOption, sv, BufferLength); +} + +sal_Int32 OResultSet::getResultSetConcurrency() const +{ + sal_uInt32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY); + if(SQL_CONCUR_READ_ONLY == nValue) + nValue = ResultSetConcurrency::READ_ONLY; + else + nValue = ResultSetConcurrency::UPDATABLE; + + return nValue; +} + +sal_Int32 OResultSet::getResultSetType() const +{ + sal_uInt32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SENSITIVITY); + if(SQL_SENSITIVE == nValue) + nValue = ResultSetType::SCROLL_SENSITIVE; + else if(SQL_INSENSITIVE == nValue) + nValue = ResultSetType::SCROLL_INSENSITIVE; + else + { + SQLULEN nCurType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE); + if(SQL_CURSOR_KEYSET_DRIVEN == nCurType) + nValue = ResultSetType::SCROLL_SENSITIVE; + else if(SQL_CURSOR_STATIC == nCurType) + nValue = ResultSetType::SCROLL_INSENSITIVE; + else if(SQL_CURSOR_FORWARD_ONLY == nCurType) + nValue = ResultSetType::FORWARD_ONLY; + else if(SQL_CURSOR_DYNAMIC == nCurType) + nValue = ResultSetType::SCROLL_SENSITIVE; + } + return nValue; +} + +sal_Int32 OResultSet::getFetchSize() const +{ + return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE); +} + +OUString OResultSet::getCursorName() const +{ + SQLCHAR pName[258]; + SQLSMALLINT nRealLen = 0; + N3SQLGetCursorName(m_aStatementHandle,pName,256,&nRealLen); + return OUString::createFromAscii(reinterpret_cast<char*>(pName)); +} + +bool OResultSet::isBookmarkable() const +{ + if(!m_aConnectionHandle) + return false; + + const SQLULEN nCursorType = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE); + + sal_Int32 nAttr = 0; + try + { + switch(nCursorType) + { + case SQL_CURSOR_FORWARD_ONLY: + return false; + case SQL_CURSOR_STATIC: + OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_STATIC_CURSOR_ATTRIBUTES1,nAttr,nullptr); + break; + case SQL_CURSOR_KEYSET_DRIVEN: + OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_KEYSET_CURSOR_ATTRIBUTES1,nAttr,nullptr); + break; + case SQL_CURSOR_DYNAMIC: + OTools::GetInfo(m_pStatement->getOwnConnection(),m_aConnectionHandle,SQL_DYNAMIC_CURSOR_ATTRIBUTES1,nAttr,nullptr); + break; + } + } + catch(const Exception&) + { + return false; + } + + if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED ) + { + m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS); + } + + return (m_nUseBookmarks != SQL_UB_OFF) && (nAttr & SQL_CA1_BOOKMARK) == SQL_CA1_BOOKMARK; +} + +void OResultSet::setFetchDirection(sal_Int32 _par0) +{ + ::dbtools::throwFunctionNotSupportedSQLException( "setFetchDirection", *this ); + + OSL_ENSURE(_par0>0,"Illegal fetch direction!"); + if ( _par0 > 0 ) + { + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, _par0); + } +} + +void OResultSet::setFetchSize(sal_Int32 _par0) +{ + OSL_ENSURE(_par0>0,"Illegal fetch size!"); + if ( _par0 != 1 ) + { + throw css::beans::PropertyVetoException("SDBC/ODBC layer not prepared for fetchSize > 1", *this); + } + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE, _par0); + m_pRowStatusArray.reset( new SQLUSMALLINT[_par0] ); + setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray.get()); +} + +IPropertyArrayHelper* OResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps(6); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), + PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::READONLY); + + return new OPropertyArrayHelper(aProps); +} + +IPropertyArrayHelper & OResultSet::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool OResultSet::convertFastPropertyValue( + Any & rConvertedValue, + Any & rOldValue, + sal_Int32 nHandle, + const Any& rValue ) +{ + switch(nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw css::lang::IllegalArgumentException(); + case PROPERTY_ID_FETCHDIRECTION: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection()); + case PROPERTY_ID_FETCHSIZE: + return ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize()); + default: + ; + } + return false; +} + +void OResultSet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const Any& rValue + ) +{ + switch(nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + case PROPERTY_ID_CURSORNAME: + case PROPERTY_ID_RESULTSETCONCURRENCY: + case PROPERTY_ID_RESULTSETTYPE: + throw Exception("cannot set prop " + OUString::number(nHandle), nullptr); + case PROPERTY_ID_FETCHDIRECTION: + setFetchDirection(getINT32(rValue)); + break; + case PROPERTY_ID_FETCHSIZE: + setFetchSize(getINT32(rValue)); + break; + default: + ; + } +} + +void OResultSet::getFastPropertyValue( + Any& rValue, + sal_Int32 nHandle + ) const +{ + switch(nHandle) + { + case PROPERTY_ID_ISBOOKMARKABLE: + rValue <<= isBookmarkable(); + break; + case PROPERTY_ID_CURSORNAME: + rValue <<= getCursorName(); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= getResultSetConcurrency(); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= getResultSetType(); + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= getFetchDirection(); + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= getFetchSize(); + break; + } +} + +void OResultSet::fillColumn(const sal_Int32 _nColumn) +{ + ensureCacheForColumn(_nColumn); + + if (m_aRow[_nColumn].isBound()) + return; + + sal_Int32 curCol; + if(m_bFetchDataInOrder) + { + // m_aRow necessarily has a prefix of bound values, then all unbound values + // EXCEPT for column 0 + // so use binary search to find the earliest unbound value before or at _nColumn + sal_Int32 lower=0; + sal_Int32 upper=_nColumn; + + while (lower < upper) + { + const sal_Int32 middle=(upper-lower)/2 + lower; + if(m_aRow[middle].isBound()) + { + lower=middle+1; + } + else + { + upper=middle; + } + } + + curCol = upper; + } + else + { + curCol = _nColumn; + } + + TDataRow::iterator pColumn = m_aRow.begin() + curCol; + const TDataRow::const_iterator pColumnEnd = m_aRow.begin() + _nColumn + 1; + + if(curCol==0) + { + try + { + *pColumn=impl_getBookmark(); + } + catch (SQLException &) + { + pColumn->setNull(); + } + pColumn->setBound(true); + ++curCol; + ++pColumn; + } + + for (; pColumn != pColumnEnd; ++curCol, ++pColumn) + { + const sal_Int32 nType = pColumn->getTypeKind(); + switch (nType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::LONGVARCHAR: + case DataType::CLOB: + *pColumn=impl_getString(curCol); + break; + case DataType::FLOAT: + *pColumn = impl_getValue<float>(curCol, SQL_C_FLOAT); + break; + case DataType::REAL: + case DataType::DOUBLE: + *pColumn = impl_getValue<double>(curCol, SQL_C_DOUBLE); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + *pColumn = impl_getBytes(curCol); + break; + case DataType::DATE: + *pColumn = impl_getDate(curCol); + break; + case DataType::TIME: + *pColumn = impl_getTime(curCol); + break; + case DataType::TIMESTAMP: + *pColumn = impl_getTimestamp(curCol); + break; + case DataType::BIT: + *pColumn = impl_getBoolean(curCol); + break; + case DataType::TINYINT: + *pColumn = impl_getValue<sal_Int8>(curCol, SQL_C_TINYINT); + break; + case DataType::SMALLINT: + *pColumn = impl_getValue<sal_Int16>(curCol, SQL_C_SHORT); + break; + case DataType::INTEGER: + *pColumn = impl_getValue<sal_Int32>(curCol, SQL_C_LONG); + break; + case DataType::BIGINT: + *pColumn = impl_getLong(curCol); + break; + default: + SAL_WARN( "connectivity.odbc","Unknown DataType"); + } + + if ( m_bWasNull ) + pColumn->setNull(); + pColumn->setBound(true); + if(nType != pColumn->getTypeKind()) + { + pColumn->setTypeKind(nType); + } + } +} + +void SAL_CALL OResultSet::acquire() throw() +{ + OResultSet_BASE::acquire(); +} + +void SAL_CALL OResultSet::release() throw() +{ + OResultSet_BASE::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +bool OResultSet::move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool /*_bRetrieveData*/) +{ + SQLSMALLINT nFetchOrientation = SQL_FETCH_NEXT; + switch(_eCursorPosition) + { + case IResultSetHelper::NEXT: + nFetchOrientation = SQL_FETCH_NEXT; + break; + case IResultSetHelper::PRIOR: + nFetchOrientation = SQL_FETCH_PRIOR; + break; + case IResultSetHelper::FIRST: + nFetchOrientation = SQL_FETCH_FIRST; + break; + case IResultSetHelper::LAST: + nFetchOrientation = SQL_FETCH_LAST; + break; + case IResultSetHelper::RELATIVE1: + nFetchOrientation = SQL_FETCH_RELATIVE; + break; + case IResultSetHelper::ABSOLUTE1: + nFetchOrientation = SQL_FETCH_ABSOLUTE; + break; + case IResultSetHelper::BOOKMARK: // special case here because we are only called with position numbers + { + TBookmarkPosMap::const_iterator aIter = std::find_if(m_aPosToBookmarks.begin(), m_aPosToBookmarks.end(), + [&_nOffset](const TBookmarkPosMap::value_type& rEntry) { return rEntry.second == _nOffset; }); + if (aIter != m_aPosToBookmarks.end()) + return moveToBookmark(makeAny(aIter->first)); + SAL_WARN( "connectivity.odbc", "Bookmark not found!"); + } + return false; + } + + m_bEOF = false; + invalidateCache(); + + SQLRETURN nOldFetchStatus = m_nCurrentFetchState; + // TODO FIXME: both of these will misbehave for + // _eCursorPosition == IResultSetHelper::NEXT/PREVIOUS + // when fetchSize > 1 + if ( !m_bUseFetchScroll && _eCursorPosition == IResultSetHelper::NEXT ) + m_nCurrentFetchState = N3SQLFetch(m_aStatementHandle); + else + m_nCurrentFetchState = N3SQLFetchScroll(m_aStatementHandle,nFetchOrientation,_nOffset); + + SAL_INFO( + "connectivity.odbc", + "move(" << nFetchOrientation << "," << _nOffset << "), FetchState = " + << m_nCurrentFetchState); + OTools::ThrowException(m_pStatement->getOwnConnection(),m_nCurrentFetchState,m_aStatementHandle,SQL_HANDLE_STMT,*this); + + const bool bSuccess = m_nCurrentFetchState == SQL_SUCCESS || m_nCurrentFetchState == SQL_SUCCESS_WITH_INFO; + if ( bSuccess ) + { + switch(_eCursorPosition) + { + case IResultSetHelper::NEXT: + ++m_nRowPos; + break; + case IResultSetHelper::PRIOR: + --m_nRowPos; + break; + case IResultSetHelper::FIRST: + m_nRowPos = 1; + break; + case IResultSetHelper::LAST: + m_bEOF = true; + break; + case IResultSetHelper::RELATIVE1: + m_nRowPos += _nOffset; + break; + case IResultSetHelper::ABSOLUTE1: + case IResultSetHelper::BOOKMARK: // special case here because we are only called with position numbers + m_nRowPos = _nOffset; + break; + } // switch(_eCursorPosition) + if ( m_nUseBookmarks == ODBC_SQL_NOT_DEFINED ) + { + m_nUseBookmarks = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS); + } + if ( m_nUseBookmarks == SQL_UB_OFF ) + { + m_aRow[0].setNull(); + } + else + { + ensureCacheForColumn(0); + Sequence<sal_Int8> bookmark = OTools::getBytesValue(m_pStatement->getOwnConnection(),m_aStatementHandle,0,SQL_C_VARBOOKMARK,m_bWasNull,**this); + m_aPosToBookmarks[bookmark] = m_nRowPos; + OSL_ENSURE(bookmark.hasElements(),"Invalid bookmark from length 0!"); + m_aRow[0] = bookmark; + } + m_aRow[0].setBound(true); + } + else if ( IResultSetHelper::PRIOR == _eCursorPosition && m_nCurrentFetchState == SQL_NO_DATA ) + // we went beforeFirst + m_nRowPos = 0; + else if(IResultSetHelper::NEXT == _eCursorPosition && m_nCurrentFetchState == SQL_NO_DATA && nOldFetchStatus != SQL_NO_DATA) + // we went afterLast + ++m_nRowPos; + + return bSuccess; +} + +sal_Int32 OResultSet::getDriverPos() const +{ + sal_Int32 nValue = getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_NUMBER); + SAL_INFO( + "connectivity.odbc", + "RowNum = " << nValue << ", RowPos = " << m_nRowPos); + return nValue ? nValue : m_nRowPos; +} + +bool OResultSet::isRowDeleted() const +{ + return m_pRowStatusArray[0] == SQL_ROW_DELETED; +} + +bool OResultSet::moveImpl(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + return (m_pSkipDeletedSet != nullptr) + ? m_pSkipDeletedSet->skipDeleted(_eCursorPosition,_nOffset,true/*_bRetrieveData*/) + : move(_eCursorPosition,_nOffset,true/*_bRetrieveData*/); +} + +void OResultSet::fillNeededData(SQLRETURN _nRet) +{ + SQLRETURN nRet = _nRet; + if( nRet != SQL_NEED_DATA) + return; + + void* pColumnIndex = nullptr; + nRet = N3SQLParamData(m_aStatementHandle,&pColumnIndex); + + do + { + if (nRet != SQL_SUCCESS && nRet != SQL_SUCCESS_WITH_INFO && nRet != SQL_NEED_DATA) + break; + + sal_IntPtr nColumnIndex ( reinterpret_cast<sal_IntPtr>(pColumnIndex)); + Sequence< sal_Int8 > aSeq; + switch(m_aRow[nColumnIndex].getTypeKind()) + { + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + aSeq = m_aRow[nColumnIndex]; + N3SQLPutData (m_aStatementHandle, aSeq.getArray(), aSeq.getLength()); + break; + case SQL_WLONGVARCHAR: + { + OUString const & sRet = m_aRow[nColumnIndex].getString(); + N3SQLPutData (m_aStatementHandle, static_cast<SQLPOINTER>(const_cast<sal_Unicode *>(sRet.getStr())), sizeof(sal_Unicode)*sRet.getLength()); + break; + } + case DataType::LONGVARCHAR: + case DataType::CLOB: + { + OUString sRet = m_aRow[nColumnIndex].getString(); + OString aString(OUStringToOString(sRet,m_nTextEncoding)); + N3SQLPutData (m_aStatementHandle, static_cast<SQLPOINTER>(const_cast<char *>(aString.getStr())), aString.getLength()); + break; + } + default: + SAL_WARN( "connectivity.odbc", "Not supported at the moment!"); + } + nRet = N3SQLParamData(m_aStatementHandle,&pColumnIndex); + } + while (nRet == SQL_NEED_DATA); +} + +SWORD OResultSet::impl_getColumnType_nothrow(sal_Int32 columnIndex) +{ + std::map<sal_Int32,SWORD>::const_iterator aFind = m_aODBCColumnTypes.find(columnIndex); + if ( aFind == m_aODBCColumnTypes.end() ) + aFind = m_aODBCColumnTypes.emplace( + columnIndex, + OResultSetMetaData::getColumnODBCType(m_pStatement->getOwnConnection(),m_aStatementHandle,*this,columnIndex) + ).first; + return aFind->second; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/OResultSetMetaData.cxx b/connectivity/source/drivers/odbc/OResultSetMetaData.cxx new file mode 100644 index 000000000..21b95c6a7 --- /dev/null +++ b/connectivity/source/drivers/odbc/OResultSetMetaData.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 <odbc/OResultSetMetaData.hxx> +#include <odbc/OTools.hxx> + +using namespace connectivity::odbc; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; + + +OResultSetMetaData::~OResultSetMetaData() +{ +} + +OUString OResultSetMetaData::getCharColAttrib(sal_Int32 _column,sal_Int32 ident) +{ + sal_Int32 column = _column; + if(_column <static_cast<sal_Int32>(m_vMapping.size())) // use mapping + column = m_vMapping[_column]; + + SQLSMALLINT BUFFER_LEN = 128; + std::unique_ptr<char[]> pName(new char[BUFFER_LEN+1]); + SQLSMALLINT nRealLen=0; + SQLRETURN nRet = N3SQLColAttribute(m_aStatementHandle, + static_cast<SQLUSMALLINT>(column), + static_cast<SQLUSMALLINT>(ident), + static_cast<SQLPOINTER>(pName.get()), + BUFFER_LEN, + &nRealLen, + nullptr + ); + OUString sValue; + if ( nRet == SQL_SUCCESS ) + { + if ( nRealLen < 0 ) + nRealLen = BUFFER_LEN; + sValue = OUString(pName.get(),nRealLen,m_pConnection->getTextEncoding()); + } + pName.reset(); + OTools::ThrowException(m_pConnection,nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + if(nRealLen > BUFFER_LEN) + { + pName.reset(new char[nRealLen+1]); + nRet = N3SQLColAttribute(m_aStatementHandle, + static_cast<SQLUSMALLINT>(column), + static_cast<SQLUSMALLINT>(ident), + static_cast<SQLPOINTER>(pName.get()), + nRealLen, + &nRealLen, + nullptr + ); + if ( nRet == SQL_SUCCESS && nRealLen > 0) + sValue = OUString(pName.get(),nRealLen,m_pConnection->getTextEncoding()); + OTools::ThrowException(m_pConnection,nRet,m_aStatementHandle,SQL_HANDLE_STMT,*this); + } + + return sValue; +} + +SQLLEN OResultSetMetaData::getNumColAttrib(OConnection const * _pConnection + ,SQLHANDLE _aStatementHandle + ,const css::uno::Reference< css::uno::XInterface >& _xInterface + ,sal_Int32 _column + ,sal_Int32 _ident) +{ + SQLLEN nValue=0; + OTools::ThrowException(_pConnection,(*reinterpret_cast<T3SQLColAttribute>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::ColAttribute)))(_aStatementHandle, + static_cast<SQLUSMALLINT>(_column), + static_cast<SQLUSMALLINT>(_ident), + nullptr, + 0, + nullptr, + &nValue),_aStatementHandle,SQL_HANDLE_STMT,_xInterface); + return nValue; +} + +sal_Int32 OResultSetMetaData::getNumColAttrib(sal_Int32 _column,sal_Int32 ident) +{ + sal_Int32 column = _column; + if(_column < static_cast<sal_Int32>(m_vMapping.size())) // use mapping + column = m_vMapping[_column]; + + return getNumColAttrib(m_pConnection,m_aStatementHandle,*this,column,ident); +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_DISPLAY_SIZE); +} + +SQLSMALLINT OResultSetMetaData::getColumnODBCType(OConnection const * _pConnection + ,SQLHANDLE _aStatementHandle + ,const css::uno::Reference< css::uno::XInterface >& _xInterface + ,sal_Int32 column) +{ + SQLSMALLINT nType = 0; + try + { + nType = static_cast<SQLSMALLINT>(getNumColAttrib(_pConnection,_aStatementHandle,_xInterface,column,SQL_DESC_CONCISE_TYPE)); + if(nType == SQL_UNKNOWN_TYPE) + nType = static_cast<SQLSMALLINT>(getNumColAttrib(_pConnection,_aStatementHandle,_xInterface,column, SQL_DESC_TYPE)); + } + catch(SQLException& ) // in this case we have an odbc 2.0 driver + { + nType = static_cast<SQLSMALLINT>(getNumColAttrib(_pConnection,_aStatementHandle,_xInterface,column,SQL_DESC_CONCISE_TYPE )); + } + + return nType; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 column ) +{ + std::map<sal_Int32,sal_Int32>::iterator aFind = m_aColumnTypes.find(column); + if ( aFind == m_aColumnTypes.end() ) + { + sal_Int32 nType = 0; + if(!m_bUseODBC2Types) + { + try + { + nType = getNumColAttrib(column,SQL_DESC_CONCISE_TYPE); + if(nType == SQL_UNKNOWN_TYPE) + nType = getNumColAttrib(column, SQL_DESC_TYPE); + nType = OTools::MapOdbcType2Jdbc(nType); + } + catch(SQLException& ) // in this case we have an odbc 2.0 driver + { + m_bUseODBC2Types = true; + nType = OTools::MapOdbcType2Jdbc(getNumColAttrib(column,SQL_DESC_CONCISE_TYPE )); + } + } + else + nType = OTools::MapOdbcType2Jdbc(getNumColAttrib(column,SQL_DESC_CONCISE_TYPE )); + aFind = m_aColumnTypes.emplace(column,nType).first; + } + + + return aFind->second; +} + + +sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount( ) +{ + if(m_nColCount != -1) + return m_nColCount; + sal_Int16 nNumResultCols=0; + OTools::ThrowException(m_pConnection,N3SQLNumResultCols(m_aStatementHandle,&nNumResultCols),m_aStatementHandle,SQL_HANDLE_STMT,*this); + m_nColCount = nNumResultCols; + return m_nColCount; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_CASE_SENSITIVE) == SQL_TRUE; +} + + +OUString SAL_CALL OResultSetMetaData::getSchemaName( sal_Int32 column ) +{ + return getCharColAttrib(column,SQL_DESC_SCHEMA_NAME); +} + + +OUString SAL_CALL OResultSetMetaData::getColumnName( sal_Int32 column ) +{ + return getCharColAttrib(column,SQL_DESC_NAME); +} + +OUString SAL_CALL OResultSetMetaData::getTableName( sal_Int32 column ) +{ + return getCharColAttrib(column,SQL_DESC_TABLE_NAME); +} + +OUString SAL_CALL OResultSetMetaData::getCatalogName( sal_Int32 column ) +{ + return getCharColAttrib(column,SQL_DESC_CATALOG_NAME); +} + +OUString SAL_CALL OResultSetMetaData::getColumnTypeName( sal_Int32 column ) +{ + return getCharColAttrib(column,SQL_DESC_TYPE_NAME); +} + +OUString SAL_CALL OResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + return getCharColAttrib(column,SQL_DESC_LABEL); +} + +OUString SAL_CALL OResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ ) +{ + return OUString(); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isCurrency( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_FIXED_PREC_SCALE) == SQL_TRUE; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_AUTO_UNIQUE_VALUE) == SQL_TRUE; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_UNSIGNED) == SQL_FALSE; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column ) +{ + sal_Int32 nType = 0; + try + { + nType = getNumColAttrib(column,SQL_DESC_PRECISION); + } + catch(const SQLException& ) // in this case we have an odbc 2.0 driver + { + m_bUseODBC2Types = true; + nType = getNumColAttrib(column,SQL_COLUMN_PRECISION ); + } + return nType; +} + +sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column ) +{ + sal_Int32 nType = 0; + try + { + nType = getNumColAttrib(column,SQL_DESC_SCALE); + } + catch(const SQLException& ) // in this case we have an odbc 2.0 driver + { + m_bUseODBC2Types = true; + nType = getNumColAttrib(column,SQL_COLUMN_SCALE ); + } + return nType; +} + + +sal_Int32 SAL_CALL OResultSetMetaData::isNullable( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_NULLABLE); +} + + +sal_Bool SAL_CALL OResultSetMetaData::isSearchable( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_SEARCHABLE) != SQL_PRED_NONE; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isReadOnly( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_UPDATABLE) == SQL_ATTR_READONLY; +} + + +sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_UPDATABLE) == SQL_ATTR_WRITE; +} + +sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 column ) +{ + return getNumColAttrib(column,SQL_DESC_UPDATABLE) == SQL_ATTR_WRITE; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/OStatement.cxx b/connectivity/source/drivers/odbc/OStatement.cxx new file mode 100644 index 000000000..6e0a37169 --- /dev/null +++ b/connectivity/source/drivers/odbc/OStatement.cxx @@ -0,0 +1,1102 @@ +/* -*- 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 <osl/diagnose.h> +#include <odbc/OStatement.hxx> +#include <odbc/OConnection.hxx> +#include <odbc/OResultSet.hxx> +#include <comphelper/property.hxx> +#include <odbc/OTools.hxx> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <comphelper/sequence.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/types.hxx> +#include <rtl/strbuf.hxx> +#include <algorithm> +#include <strings.hrc> +#include <connectivity/dbexception.hxx> + +using namespace ::comphelper; + +#define THROW_SQL(x) \ + OTools::ThrowException(m_pConnection.get(),x,m_aStatementHandle,SQL_HANDLE_STMT,*this) + + +using namespace connectivity::odbc; + +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::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +OStatement_Base::OStatement_Base(OConnection* _pConnection ) + :OStatement_BASE(m_aMutex) + ,OPropertySetHelper(OStatement_BASE::rBHelper) + ,m_pConnection(_pConnection) + ,m_aStatementHandle(SQL_NULL_HANDLE) + ,m_pRowStatusArray(nullptr) +{ + osl_atomic_increment( &m_refCount ); + m_aStatementHandle = m_pConnection->createStatementHandle(); + + //setMaxFieldSize(0); + // Don't do this. By ODBC spec, "0" is the default for the SQL_ATTR_MAX_LENGTH attribute. We once introduced + // this line since a PostgreSQL ODBC driver had a default other than 0. However, current drivers (at least 8.3 + // and later) have a proper default of 0, so there should be no need anymore. + // On the other hand, the NotesSQL driver (IBM's ODBC driver for the Lotus Notes series) wrongly interprets + // "0" as "0", whereas the ODBC spec says it should in fact mean "unlimited". + // So, removing this line seems to be the best option for now. + // If we ever again encounter an ODBC driver which needs this option, then we should introduce a data source + // setting for it, instead of unconditionally doing it. + + osl_atomic_decrement( &m_refCount ); +} + +OStatement_Base::~OStatement_Base() +{ + OSL_ENSURE(!m_aStatementHandle,"Sohould ne null here!"); +} + +void OStatement_Base::disposeResultSet() +{ + // free the cursor if alive + Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + m_xResultSet.clear(); +} + +void SAL_CALL OStatement_Base::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + disposeResultSet(); + ::comphelper::disposeComponent(m_xGeneratedStatement); + + OSL_ENSURE(m_aStatementHandle,"OStatement_BASE2::disposing: StatementHandle is null!"); + if (m_pConnection.is()) + { + m_pConnection->freeStatementHandle(m_aStatementHandle); + m_pConnection.clear(); + } + OSL_ENSURE(!m_aStatementHandle,"Sohould ne null here!"); + + OStatement_BASE::disposing(); +} + +void OStatement_BASE2::disposing() +{ + ::osl::MutexGuard aGuard1(m_aMutex); + OStatement_Base::disposing(); +} + +Any SAL_CALL OStatement_Base::queryInterface( const Type & rType ) +{ + if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() && rType == cppu::UnoType<XGeneratedResultSet>::get()) + return Any(); + Any aRet = OStatement_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OStatement_Base::getTypes( ) +{ + ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get()); + Sequence< Type > aOldTypes = OStatement_BASE::getTypes(); + if ( m_pConnection.is() && !m_pConnection->isAutoRetrievingEnabled() ) + { + auto newEnd = std::remove(aOldTypes.begin(), aOldTypes.end(), + cppu::UnoType<XGeneratedResultSet>::get()); + aOldTypes.realloc(std::distance(aOldTypes.begin(), newEnd)); + } + + return ::comphelper::concatSequences(aTypes.getTypes(),aOldTypes); +} + +Reference< XResultSet > SAL_CALL OStatement_Base::getGeneratedValues( ) +{ + OSL_ENSURE( m_pConnection.is() && m_pConnection->isAutoRetrievingEnabled(),"Illegal call here. isAutoRetrievingEnabled is false!"); + Reference< XResultSet > xRes; + if ( m_pConnection.is() ) + { + OUString sStmt = m_pConnection->getTransformedGeneratedStatement(m_sSqlStatement); + if ( !sStmt.isEmpty() ) + { + ::comphelper::disposeComponent(m_xGeneratedStatement); + m_xGeneratedStatement = m_pConnection->createStatement(); + xRes = m_xGeneratedStatement->executeQuery(sStmt); + } + } + return xRes; +} + +void SAL_CALL OStatement_Base::cancel( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + N3SQLCancel(m_aStatementHandle); +} + + +void SAL_CALL OStatement_Base::close( ) +{ + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + } + dispose(); +} + + +void SAL_CALL OStatement::clearBatch( ) +{ + +} + +void OStatement_Base::reset() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + clearWarnings (); + + if (m_xResultSet.get().is()) + { + clearMyResultSet(); + } + if(m_aStatementHandle) + { + THROW_SQL(N3SQLFreeStmt(m_aStatementHandle, SQL_CLOSE)); + } +} + +// clearMyResultSet +// If a ResultSet was created for this Statement, close it +void OStatement_Base::clearMyResultSet() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + try + { + Reference<XCloseable> xCloseable( + m_xResultSet.get(), css::uno::UNO_QUERY); + if ( xCloseable.is() ) + xCloseable->close(); + } + catch( const DisposedException& ) { } + + m_xResultSet.clear(); +} + +SQLLEN OStatement_Base::getRowCount() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + SQLLEN numRows = 0; + + try { + THROW_SQL(N3SQLRowCount(m_aStatementHandle,&numRows)); + } + catch (const SQLException&) + { + } + return numRows; +} + +// lockIfNecessary +// If the given SQL statement contains a 'FOR UPDATE' clause, change +// the concurrency to lock so that the row can then be updated. Returns +// true if the concurrency has been changed +bool OStatement_Base::lockIfNecessary (const OUString& sql) +{ + bool rc = false; + + // First, convert the statement to upper case + + OUString sqlStatement = sql.toAsciiUpperCase (); + + // Now, look for the FOR UPDATE keywords. If there is any extra white + // space between the FOR and UPDATE, this will fail. + + sal_Int32 index = sqlStatement.indexOf(" FOR UPDATE"); + + // We found it. Change our concurrency level to ensure that the + // row can be updated. + + if (index > 0) + { + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + try + { + THROW_SQL((setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY, SQL_CONCUR_LOCK))); + } + catch (const SQLWarning& warn) + { + // Catch any warnings and place on the warning stack + setWarning (warn); + } + rc = true; + } + + return rc; +} + +// setWarning +// Sets the warning + + +void OStatement_Base::setWarning (const SQLWarning &ex) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_aLastWarning = ex; +} + + +// getColumnCount +// Return the number of columns in the ResultSet +sal_Int32 OStatement_Base::getColumnCount() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + sal_Int16 numCols = 0; + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + + try { + THROW_SQL(N3SQLNumResultCols(m_aStatementHandle,&numCols)); + } + catch (const SQLException&) + { + } + return numCols; +} + + +sal_Bool SAL_CALL OStatement_Base::execute( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + m_sSqlStatement = sql; + + + OString aSql(OUStringToOString(sql,getOwnConnection()->getTextEncoding())); + + bool hasResultSet = false; + SQLWarning aWarning; + + // Reset the statement handle and warning + + reset(); + + // Check for a 'FOR UPDATE' statement. If present, change + // the concurrency to lock + + lockIfNecessary (sql); + + // Call SQLExecDirect + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + + try { + THROW_SQL(N3SQLExecDirect(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())), aSql.getLength())); + } + catch (const SQLWarning& ex) { + + // Save pointer to warning and save with ResultSet + // object once it is created. + + aWarning = ex; + } + + // Now determine if there is a result set associated with + // the SQL statement that was executed. Get the column + // count, and if it is not zero, there is a result set. + + if (getColumnCount () > 0) + { + hasResultSet = true; + } + + return hasResultSet; +} + +// getResultSet +// getResultSet returns the current result as a ResultSet. It +// returns NULL if the current result is not a ResultSet. + +Reference< XResultSet > OStatement_Base::getResultSet(bool checkCount) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + if (m_xResultSet.get().is()) // if resultset already retrieved, + { + // throw exception to avoid sequence error + ::dbtools::throwFunctionSequenceException(*this); + } + + OResultSet* pRs = nullptr; + sal_Int32 numCols = 1; + + // If we already know we have result columns, checkCount + // is false. This is an optimization to prevent unneeded + // calls to getColumnCount + + if (checkCount) + numCols = getColumnCount (); + + // Only return a result set if there are result columns + + if (numCols > 0) + { + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + pRs = createResulSet(); + pRs->construct(); + + // Save a copy of our last result set + // Changed to save copy at getResultSet. + //m_xResultSet = rs; + } + else + clearMyResultSet (); + + return pRs; +} + +// getStmtOption +// Invoke SQLGetStmtOption with the given option. + + +template < typename T, SQLINTEGER BufferLength > T OStatement_Base::getStmtOption (SQLINTEGER fOption) const +{ + T result (0); + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + N3SQLGetStmtAttr(m_aStatementHandle, fOption, &result, BufferLength, nullptr); + return result; +} +template < typename T, SQLINTEGER BufferLength > SQLRETURN OStatement_Base::setStmtOption (SQLINTEGER fOption, T value) const +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLPOINTER sv = reinterpret_cast<SQLPOINTER>(value); + return N3SQLSetStmtAttr(m_aStatementHandle, fOption, sv, BufferLength); +} + + +Reference< XResultSet > SAL_CALL OStatement_Base::executeQuery( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + Reference< XResultSet > xRS; + + // Execute the statement. If execute returns true, a result + // set exists. + + if (execute (sql)) + { + xRS = getResultSet (false); + m_xResultSet = xRS; + } + else + { + // No ResultSet was produced. Raise an exception + m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this); + } + return xRS; +} + + +Reference< XConnection > SAL_CALL OStatement_Base::getConnection( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + return Reference< XConnection >(m_pConnection.get()); +} + + +Any SAL_CALL OStatement::queryInterface( const Type & rType ) +{ + Any aRet = ::cppu::queryInterface(rType,static_cast< XBatchExecution*> (this)); + return aRet.hasValue() ? aRet : OStatement_Base::queryInterface(rType); +} + + +void SAL_CALL OStatement::addBatch( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_aBatchVector.push_back(sql); +} + +Sequence< sal_Int32 > SAL_CALL OStatement::executeBatch( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + OStringBuffer aBatchSql; + sal_Int32 nLen = m_aBatchVector.size(); + + for (auto const& elem : m_aBatchVector) + { + aBatchSql.append(OUStringToOString(elem,getOwnConnection()->getTextEncoding())); + aBatchSql.append(";"); + } + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + auto s = aBatchSql.makeStringAndClear(); + THROW_SQL(N3SQLExecDirect(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(s.getStr())), s.getLength())); + + Sequence< sal_Int32 > aRet(nLen); + sal_Int32* pArray = aRet.getArray(); + for(sal_Int32 j=0;j<nLen;++j) + { + SQLRETURN nError = N3SQLMoreResults(m_aStatementHandle); + if(nError == SQL_SUCCESS) + { + SQLLEN nRowCount=0; + N3SQLRowCount(m_aStatementHandle,&nRowCount); + pArray[j] = nRowCount; + } + } + return aRet; +} + + +sal_Int32 SAL_CALL OStatement_Base::executeUpdate( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + sal_Int32 numRows = -1; + + // Execute the statement. If execute returns false, a + // row count exists. + + if (!execute (sql)) { + numRows = getUpdateCount(); + } + else { + + // No update count was produced (a ResultSet was). Raise + // an exception + + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceString(STR_NO_ROWCOUNT)); + throw SQLException (sError, *this,OUString(),0,Any()); + } + return numRows; + +} + + +Reference< XResultSet > SAL_CALL OStatement_Base::getResultSet( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_xResultSet = getResultSet(true); + return m_xResultSet; +} + + +sal_Int32 SAL_CALL OStatement_Base::getUpdateCount( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + sal_Int32 rowCount = -1; + + // Only return a row count for SQL statements that did not + // return a result set. + + if (getColumnCount () == 0) + rowCount = getRowCount (); + + return rowCount; +} + + +sal_Bool SAL_CALL OStatement_Base::getMoreResults( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + SQLWarning warning; + bool hasResultSet = false; + + // clear previous warnings + + clearWarnings (); + + // Call SQLMoreResults + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + + try { + hasResultSet = N3SQLMoreResults(m_aStatementHandle) == SQL_SUCCESS; + } + catch (const SQLWarning &ex) { + + // Save pointer to warning and save with ResultSet + // object once it is created. + + warning = ex; + } + + // There are more results (it may not be a result set, though) + + if (hasResultSet) + { + + // Now determine if there is a result set associated + // with the SQL statement that was executed. Get the + // column count, and if it is zero, there is not a + // result set. + + if (getColumnCount () == 0) + hasResultSet = false; + } + + // Set the warning for the statement, if one was generated + + setWarning (warning); + + // Return the result set indicator + + return hasResultSet; +} + + +Any SAL_CALL OStatement_Base::getWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + return makeAny(m_aLastWarning); +} + + +void SAL_CALL OStatement_Base::clearWarnings( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + m_aLastWarning = SQLWarning(); +} + + +sal_Int64 OStatement_Base::getQueryTimeOut() const +{ + return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_QUERY_TIMEOUT); +} + +sal_Int64 OStatement_Base::getMaxRows() const +{ + return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_ROWS); +} + +sal_Int32 OStatement_Base::getResultSetConcurrency() const +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY)); + if(nValue == SQL_CONCUR_READ_ONLY) + nValue = ResultSetConcurrency::READ_ONLY; + else + nValue = ResultSetConcurrency::UPDATABLE; + return nValue; +} + +sal_Int32 OStatement_Base::getResultSetType() const +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE)); + switch(nValue) + { + case SQL_CURSOR_FORWARD_ONLY: + nValue = ResultSetType::FORWARD_ONLY; + break; + case SQL_CURSOR_KEYSET_DRIVEN: + case SQL_CURSOR_STATIC: + nValue = ResultSetType::SCROLL_INSENSITIVE; + break; + case SQL_CURSOR_DYNAMIC: + nValue = ResultSetType::SCROLL_SENSITIVE; + break; + default: + OSL_FAIL("Unknown ODBC Cursor Type"); + } + + return nValue; +} + +sal_Int32 OStatement_Base::getFetchDirection() const +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLULEN nValue (getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE)); + switch(nValue) + { + case SQL_SCROLLABLE: + nValue = FetchDirection::REVERSE; + break; + default: + nValue = FetchDirection::FORWARD; + break; + } + + return nValue; +} + +sal_Int32 OStatement_Base::getFetchSize() const +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE); +} + +sal_Int64 OStatement_Base::getMaxFieldSize() const +{ + return getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_LENGTH); +} + +OUString OStatement_Base::getCursorName() const +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLCHAR pName[258]; + SQLSMALLINT nRealLen = 0; + N3SQLGetCursorName(m_aStatementHandle,pName,256,&nRealLen); + return OUString::createFromAscii(reinterpret_cast<char*>(pName)); +} + +void OStatement_Base::setQueryTimeOut(sal_Int64 seconds) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_QUERY_TIMEOUT,seconds); +} + +void OStatement_Base::setMaxRows(sal_Int64 _par0) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_ROWS, _par0); +} + +void OStatement_Base::setResultSetConcurrency(sal_Int32 _par0) +{ + SQLULEN nSet; + if(_par0 == ResultSetConcurrency::READ_ONLY) + nSet = SQL_CONCUR_READ_ONLY; + else + nSet = SQL_CONCUR_VALUES; + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CONCURRENCY, nSet); +} + +void OStatement_Base::setResultSetType(sal_Int32 _par0) +{ + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_BIND_TYPE, SQL_BIND_BY_COLUMN); + + bool bUseBookmark = isUsingBookmarks(); + SQLULEN nSet( SQL_UNSPECIFIED ); + switch(_par0) + { + case ResultSetType::FORWARD_ONLY: + nSet = SQL_UNSPECIFIED; + break; + case ResultSetType::SCROLL_INSENSITIVE: + nSet = SQL_INSENSITIVE; + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN); + break; + case ResultSetType::SCROLL_SENSITIVE: + if(bUseBookmark) + { + SQLUINTEGER nCurProp = getCursorProperties(SQL_CURSOR_DYNAMIC,true); + if((nCurProp & SQL_CA1_BOOKMARK) != SQL_CA1_BOOKMARK) // check if bookmark for this type isn't supported + { // we have to test the next one + nCurProp = getCursorProperties(SQL_CURSOR_KEYSET_DRIVEN,true); + bool bNotBookmarks = ((nCurProp & SQL_CA1_BOOKMARK) != SQL_CA1_BOOKMARK); + nCurProp = getCursorProperties(SQL_CURSOR_KEYSET_DRIVEN,false); + nSet = SQL_CURSOR_KEYSET_DRIVEN; + if( bNotBookmarks || + ((nCurProp & SQL_CA2_SENSITIVITY_DELETIONS) != SQL_CA2_SENSITIVITY_DELETIONS) || + ((nCurProp & SQL_CA2_SENSITIVITY_ADDITIONS) != SQL_CA2_SENSITIVITY_ADDITIONS)) + { + // bookmarks for keyset isn't supported so reset bookmark setting + setUsingBookmarks(false); + nSet = SQL_CURSOR_DYNAMIC; + } + } + else + nSet = SQL_CURSOR_DYNAMIC; + } + else + nSet = SQL_CURSOR_DYNAMIC; + if( setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, nSet) != SQL_SUCCESS ) + { + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_TYPE, SQL_CURSOR_KEYSET_DRIVEN); + } + nSet = SQL_SENSITIVE; + break; + default: + OSL_FAIL( "OStatement_Base::setResultSetType: invalid result set type!" ); + break; + } + + + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SENSITIVITY, nSet); +} + +void OStatement_Base::setEscapeProcessing( const bool _bEscapeProc ) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLULEN nEscapeProc( _bEscapeProc ? SQL_NOSCAN_OFF : SQL_NOSCAN_ON ); + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_NOSCAN, nEscapeProc); +} + + +void OStatement_Base::setFetchDirection(sal_Int32 _par0) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + if(_par0 == FetchDirection::FORWARD) + { + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE, SQL_NONSCROLLABLE); + } + else if(_par0 == FetchDirection::REVERSE) + { + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_CURSOR_SCROLLABLE, SQL_SCROLLABLE); + } +} + +void OStatement_Base::setFetchSize(sal_Int32 _par0) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + OSL_ENSURE(_par0>0,"Illegal fetch size!"); + if ( _par0 > 0 ) + { + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_ROW_ARRAY_SIZE, _par0); + + delete[] m_pRowStatusArray; + m_pRowStatusArray = new SQLUSMALLINT[_par0]; + setStmtOption<SQLUSMALLINT*, SQL_IS_POINTER>(SQL_ATTR_ROW_STATUS_PTR, m_pRowStatusArray); + } +} + +void OStatement_Base::setMaxFieldSize(sal_Int64 _par0) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_MAX_LENGTH, _par0); +} + +void OStatement_Base::setCursorName(const OUString &_par0) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + OString aName(OUStringToOString(_par0,getOwnConnection()->getTextEncoding())); + N3SQLSetCursorName(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aName.getStr())), static_cast<SQLSMALLINT>(aName.getLength())); +} + +bool OStatement_Base::isUsingBookmarks() const +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + return SQL_UB_OFF != getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS); +} + +bool OStatement_Base::getEscapeProcessing() const +{ + OSL_ENSURE( m_aStatementHandle, "StatementHandle is null!" ); + return SQL_NOSCAN_OFF == getStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS); +} + +void OStatement_Base::setUsingBookmarks(bool _bUseBookmark) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLULEN nValue = _bUseBookmark ? SQL_UB_VARIABLE : SQL_UB_OFF; + setStmtOption<SQLULEN, SQL_IS_UINTEGER>(SQL_ATTR_USE_BOOKMARKS, nValue); +} + +::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const +{ + Sequence< Property > aProps(10); + Property* pProperties = aProps.getArray(); + sal_Int32 nPos = 0; + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, cppu::UnoType<bool>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0); + pProperties[nPos++] = css::beans::Property(::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0); + + return new ::cppu::OPropertyArrayHelper(aProps); +} + + +::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool OStatement_Base::convertFastPropertyValue( + Any & rConvertedValue, + Any & rOldValue, + sal_Int32 nHandle, + const Any& rValue ) +{ + bool bConverted = false; + try + { + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getQueryTimeOut()); + break; + + case PROPERTY_ID_MAXFIELDSIZE: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxFieldSize()); + break; + + case PROPERTY_ID_MAXROWS: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getMaxRows()); + break; + + case PROPERTY_ID_CURSORNAME: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getCursorName()); + break; + + case PROPERTY_ID_RESULTSETCONCURRENCY: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetConcurrency()); + break; + + case PROPERTY_ID_RESULTSETTYPE: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getResultSetType()); + break; + + case PROPERTY_ID_FETCHDIRECTION: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchDirection()); + break; + + case PROPERTY_ID_FETCHSIZE: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, getFetchSize()); + break; + + case PROPERTY_ID_USEBOOKMARKS: + bConverted = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, isUsingBookmarks()); + break; + + case PROPERTY_ID_ESCAPEPROCESSING: + bConverted = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, getEscapeProcessing() ); + break; + + } + } + catch(const SQLException&) + { + // throw Exception(e.Message,*this); + } + return bConverted; +} + +void OStatement_Base::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + try + { + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + setQueryTimeOut(comphelper::getINT64(rValue)); + break; + case PROPERTY_ID_MAXFIELDSIZE: + setMaxFieldSize(comphelper::getINT64(rValue)); + break; + case PROPERTY_ID_MAXROWS: + setMaxRows(comphelper::getINT64(rValue)); + break; + case PROPERTY_ID_CURSORNAME: + setCursorName(comphelper::getString(rValue)); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + setResultSetConcurrency(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_RESULTSETTYPE: + setResultSetType(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHDIRECTION: + setFetchDirection(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHSIZE: + setFetchSize(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_USEBOOKMARKS: + setUsingBookmarks(comphelper::getBOOL(rValue)); + break; + case PROPERTY_ID_ESCAPEPROCESSING: + setEscapeProcessing( ::comphelper::getBOOL( rValue ) ); + break; + default: + OSL_FAIL( "OStatement_Base::setFastPropertyValue_NoBroadcast: what property?" ); + break; + } + } + catch(const SQLException& ) + { + // throw Exception(e.Message,*this); + } +} + +void OStatement_Base::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const +{ + switch(nHandle) + { + case PROPERTY_ID_QUERYTIMEOUT: + rValue <<= getQueryTimeOut(); + break; + case PROPERTY_ID_MAXFIELDSIZE: + rValue <<= getMaxFieldSize(); + break; + case PROPERTY_ID_MAXROWS: + rValue <<= getMaxRows(); + break; + case PROPERTY_ID_CURSORNAME: + rValue <<= getCursorName(); + break; + case PROPERTY_ID_RESULTSETCONCURRENCY: + rValue <<= getResultSetConcurrency(); + break; + case PROPERTY_ID_RESULTSETTYPE: + rValue <<= getResultSetType(); + break; + case PROPERTY_ID_FETCHDIRECTION: + rValue <<= getFetchDirection(); + break; + case PROPERTY_ID_FETCHSIZE: + rValue <<= getFetchSize(); + break; + case PROPERTY_ID_USEBOOKMARKS: + rValue <<= isUsingBookmarks(); + break; + case PROPERTY_ID_ESCAPEPROCESSING: + rValue <<= getEscapeProcessing(); + break; + default: + OSL_FAIL( "OStatement_Base::getFastPropertyValue: what property?" ); + break; + } +} + +IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbcx.OStatement","com.sun.star.sdbc.Statement"); + +void SAL_CALL OStatement_Base::acquire() throw() +{ + OStatement_BASE::acquire(); +} + +void SAL_CALL OStatement_Base::release() throw() +{ + OStatement_BASE::release(); +} + +void SAL_CALL OStatement::acquire() throw() +{ + OStatement_BASE2::acquire(); +} + +void SAL_CALL OStatement::release() throw() +{ + OStatement_BASE2::release(); +} + +OResultSet* OStatement_Base::createResulSet() +{ + return new OResultSet(m_aStatementHandle,this); +} + +Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +SQLUINTEGER OStatement_Base::getCursorProperties(SQLINTEGER _nCursorType, bool bFirst) +{ + SQLUINTEGER nValueLen = 0; + try + { + SQLUSMALLINT nAskFor = SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2; + if(SQL_CURSOR_KEYSET_DRIVEN == _nCursorType) + nAskFor = bFirst ? SQL_KEYSET_CURSOR_ATTRIBUTES1 : SQL_KEYSET_CURSOR_ATTRIBUTES2; + else if(SQL_CURSOR_STATIC == _nCursorType) + nAskFor = bFirst ? SQL_STATIC_CURSOR_ATTRIBUTES1 : SQL_STATIC_CURSOR_ATTRIBUTES2; + else if(SQL_CURSOR_FORWARD_ONLY == _nCursorType) + nAskFor = bFirst ? SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 : SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2; + else if(SQL_CURSOR_DYNAMIC == _nCursorType) + nAskFor = bFirst ? SQL_DYNAMIC_CURSOR_ATTRIBUTES1 : SQL_DYNAMIC_CURSOR_ATTRIBUTES2; + + + OTools::GetInfo(getOwnConnection(),getConnectionHandle(),nAskFor,nValueLen,nullptr); + } + catch(const Exception&) + { // we don't want our result destroy here + nValueLen = 0; + } + return nValueLen; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/OTools.cxx b/connectivity/source/drivers/odbc/OTools.cxx new file mode 100644 index 000000000..4781415de --- /dev/null +++ b/connectivity/source/drivers/odbc/OTools.cxx @@ -0,0 +1,797 @@ +/* -*- 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 <odbc/OTools.hxx> +#include <odbc/OFunctions.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> +#include <osl/endian.h> +#include <odbc/OConnection.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +#include <string.h> + +using namespace connectivity::odbc; +using namespace com::sun::star::uno; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::util; + +namespace { +size_t sqlTypeLen ( SQLSMALLINT _nType ) +{ + switch (_nType) + { + case SQL_C_SSHORT: + case SQL_C_SHORT: + return sizeof(SQLSMALLINT); + case SQL_C_USHORT: + return sizeof(SQLUSMALLINT); + case SQL_C_SLONG: + case SQL_C_LONG: + return sizeof(SQLINTEGER); + case SQL_C_ULONG: + return sizeof(SQLUINTEGER); + case SQL_C_FLOAT: + return sizeof(SQLREAL); + case SQL_C_DOUBLE: + static_assert(sizeof(SQLDOUBLE) == sizeof(SQLFLOAT), "SQLDOUBLE/SQLFLOAT confusion"); + return sizeof(SQLDOUBLE); + case SQL_C_BIT: + return sizeof(SQLCHAR); + case SQL_C_STINYINT: + case SQL_C_TINYINT: + return sizeof(SQLSCHAR); + case SQL_C_UTINYINT: + return sizeof(SQLCHAR); + case SQL_C_SBIGINT: + return sizeof(SQLBIGINT); + case SQL_C_UBIGINT: + return sizeof(SQLUBIGINT); + /* UnixODBC gives this the same value as SQL_C_UBIGINT + case SQL_C_BOOKMARK: + return sizeof(BOOKMARK); */ + case SQL_C_TYPE_DATE: + case SQL_C_DATE: + return sizeof(SQL_DATE_STRUCT); + case SQL_C_TYPE_TIME: + case SQL_C_TIME: + return sizeof(SQL_TIME_STRUCT); + case SQL_C_TYPE_TIMESTAMP: + case SQL_C_TIMESTAMP: + return sizeof(SQL_TIMESTAMP_STRUCT); + case SQL_C_NUMERIC: + return sizeof(SQL_NUMERIC_STRUCT); + case SQL_C_GUID: + return sizeof(SQLGUID); + case SQL_C_INTERVAL_YEAR: + case SQL_C_INTERVAL_MONTH: + case SQL_C_INTERVAL_DAY: + case SQL_C_INTERVAL_HOUR: + case SQL_C_INTERVAL_MINUTE: + case SQL_C_INTERVAL_SECOND: + case SQL_C_INTERVAL_YEAR_TO_MONTH: + case SQL_C_INTERVAL_DAY_TO_HOUR: + case SQL_C_INTERVAL_DAY_TO_MINUTE: + case SQL_C_INTERVAL_DAY_TO_SECOND: + case SQL_C_INTERVAL_HOUR_TO_MINUTE: + case SQL_C_INTERVAL_HOUR_TO_SECOND: + case SQL_C_INTERVAL_MINUTE_TO_SECOND: + return sizeof(SQL_INTERVAL_STRUCT); + // ** Variable-sized datatypes -> cannot predict length + case SQL_C_CHAR: + case SQL_C_WCHAR: + case SQL_C_BINARY: + // UnixODBC gives this the same value as SQL_C_BINARY + //case SQL_C_VARBOOKMARK: + // Unknown datatype -> cannot predict length + default: + return static_cast<size_t>(-1); + } +} + +void appendSQLWCHARs(OUStringBuffer & s, SQLWCHAR const * d, sal_Int32 n) +{ + static_assert( + sizeof (SQLWCHAR) == sizeof (sal_Unicode) || sizeof (SQLWCHAR) == 4, + "bad SQLWCHAR"); + if (sizeof (SQLWCHAR) == sizeof (sal_Unicode)) { + s.append(reinterpret_cast<sal_Unicode const *>(d), n); + } else { + for (sal_Int32 i = 0; i != n; ++i) { + s.appendUtf32(d[i]); + } + } +} +} + + +void OTools::getValue( OConnection const * _pConnection, + SQLHANDLE _aStatementHandle, + sal_Int32 columnIndex, + SQLSMALLINT _nType, + bool &_bWasNull, + const css::uno::Reference< css::uno::XInterface >& _xInterface, + void* _pValue, + SQLLEN _nSize) +{ + const size_t properSize = sqlTypeLen(_nType); + if ( properSize == static_cast<size_t>(-1) ) + SAL_WARN( "connectivity.drivers", "connectivity::odbc::OTools::getValue: unknown SQL type - cannot check buffer size"); + else + { + OSL_ENSURE(static_cast<size_t>(_nSize) == properSize, "connectivity::odbc::OTools::getValue got wrongly sized memory region to write result to"); + if ( o3tl::make_unsigned(_nSize) > properSize ) + { + SAL_WARN( "connectivity.drivers", "memory region is too big - trying to fudge it"); + memset(_pValue, 0, _nSize); +#ifdef OSL_BIGENDIAN + // This is skewed in favour of integer types + _pValue = static_cast<char*>(_pValue) + _nSize - properSize; +#endif + } + } + OSL_ENSURE(o3tl::make_unsigned(_nSize) >= properSize, "memory region is too small"); + SQLLEN pcbValue = SQL_NULL_DATA; + OTools::ThrowException(_pConnection, + (*reinterpret_cast<T3SQLGetData>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetData)))(_aStatementHandle, + static_cast<SQLUSMALLINT>(columnIndex), + _nType, + _pValue, + _nSize, + &pcbValue), + _aStatementHandle,SQL_HANDLE_STMT,_xInterface,false); + _bWasNull = pcbValue == SQL_NULL_DATA; +} + +void OTools::bindValue( OConnection const * _pConnection, + SQLHANDLE _aStatementHandle, + sal_Int32 columnIndex, + SQLSMALLINT _nType, + SQLSMALLINT _nMaxLen, + const void* _pValue, + void* _pData, + SQLLEN * const pLen, + const css::uno::Reference< css::uno::XInterface >& _xInterface, + rtl_TextEncoding _nTextEncoding, + bool _bUseOldTimeDate) +{ + SQLRETURN nRetcode; + SQLSMALLINT fSqlType; + SQLSMALLINT fCType; + + OTools::getBindTypes( false, + _bUseOldTimeDate, + _nType, + fCType, + fSqlType); + + if (columnIndex != 0 && !_pValue) + { + *pLen = SQL_NULL_DATA; + nRetcode = (*reinterpret_cast<T3SQLBindCol>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::BindCol)))(_aStatementHandle, + static_cast<SQLUSMALLINT>(columnIndex), + fCType, + _pData, + _nMaxLen, + pLen + ); + } + else + { + try + { + switch (_nType) + { + case SQL_CHAR: + case SQL_VARCHAR: + { + OString aString(OUStringToOString(*static_cast<OUString const *>(_pValue),_nTextEncoding)); + *pLen = SQL_NTS; + *static_cast<OString*>(_pData) = aString; + + // Pointer on Char* + _pData = const_cast<char *>(aString.getStr()); + } break; + case SQL_BIGINT: + *static_cast<sal_Int64*>(_pData) = *static_cast<sal_Int64 const *>(_pValue); + *pLen = sizeof(sal_Int64); + break; + case SQL_DECIMAL: + case SQL_NUMERIC: + { + OString aString = OString::number(*static_cast<double const *>(_pValue)); + *pLen = static_cast<SQLSMALLINT>(aString.getLength()); + *static_cast<OString*>(_pData) = aString; + // Pointer on Char* + _pData = const_cast<char *>(static_cast<OString*>(_pData)->getStr()); + } break; + case SQL_BIT: + case SQL_TINYINT: + *static_cast<sal_Int8*>(_pData) = *static_cast<sal_Int8 const *>(_pValue); + *pLen = sizeof(sal_Int8); + break; + + case SQL_SMALLINT: + *static_cast<sal_Int16*>(_pData) = *static_cast<sal_Int16 const *>(_pValue); + *pLen = sizeof(sal_Int16); + break; + case SQL_INTEGER: + *static_cast<sal_Int32*>(_pData) = *static_cast<sal_Int32 const *>(_pValue); + *pLen = sizeof(sal_Int32); + break; + case SQL_FLOAT: + *static_cast<float*>(_pData) = *static_cast<float const *>(_pValue); + *pLen = sizeof(float); + break; + case SQL_REAL: + case SQL_DOUBLE: + *static_cast<double*>(_pData) = *static_cast<double const *>(_pValue); + *pLen = sizeof(double); + break; + case SQL_BINARY: + case SQL_VARBINARY: + { + _pData = const_cast<sal_Int8 *>(static_cast<const css::uno::Sequence< sal_Int8 > *>(_pValue)->getConstArray()); + *pLen = static_cast<const css::uno::Sequence< sal_Int8 > *>(_pValue)->getLength(); + } break; + case SQL_LONGVARBINARY: + { + /* see https://msdn.microsoft.com/en-us/library/ms716238%28v=vs.85%29.aspx + * for an explanation of that apparently weird cast */ + _pData = reinterpret_cast<void*>(static_cast<uintptr_t>(columnIndex)); + sal_Int32 nLen = static_cast<const css::uno::Sequence< sal_Int8 > *>(_pValue)->getLength(); + *pLen = static_cast<SQLLEN>(SQL_LEN_DATA_AT_EXEC(nLen)); + } + break; + case SQL_LONGVARCHAR: + { + /* see https://msdn.microsoft.com/en-us/library/ms716238%28v=vs.85%29.aspx + * for an explanation of that apparently weird cast */ + _pData = reinterpret_cast<void*>(static_cast<uintptr_t>(columnIndex)); + sal_Int32 nLen = static_cast<OUString const *>(_pValue)->getLength(); + *pLen = static_cast<SQLLEN>(SQL_LEN_DATA_AT_EXEC(nLen)); + } break; + case SQL_DATE: + *pLen = sizeof(DATE_STRUCT); + *static_cast<DATE_STRUCT*>(_pData) = *static_cast<DATE_STRUCT const *>(_pValue); + break; + case SQL_TIME: + *pLen = sizeof(TIME_STRUCT); + *static_cast<TIME_STRUCT*>(_pData) = *static_cast<TIME_STRUCT const *>(_pValue); + break; + case SQL_TIMESTAMP: + *pLen = sizeof(TIMESTAMP_STRUCT); + *static_cast<TIMESTAMP_STRUCT*>(_pData) = *static_cast<TIMESTAMP_STRUCT const *>(_pValue); + break; + } + } + catch ( ... ) + { + } + + nRetcode = (*reinterpret_cast<T3SQLBindCol>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::BindCol)))(_aStatementHandle, + static_cast<SQLUSMALLINT>(columnIndex), + fCType, + _pData, + _nMaxLen, + pLen + ); + } + + OTools::ThrowException(_pConnection,nRetcode,_aStatementHandle,SQL_HANDLE_STMT,_xInterface); +} + +void OTools::ThrowException(const OConnection* _pConnection, + const SQLRETURN _rRetCode, + const SQLHANDLE _pContext, + const SQLSMALLINT _nHandleType, + const Reference< XInterface >& _xInterface, + const bool _bNoFound) +{ + switch(_rRetCode) + { + case SQL_NEED_DATA: + case SQL_STILL_EXECUTING: + case SQL_SUCCESS: + + case SQL_SUCCESS_WITH_INFO: + return; + case SQL_NO_DATA_FOUND: + if(_bNoFound) + return; // no need to throw an exception + break; + case SQL_ERROR: break; + + + case SQL_INVALID_HANDLE: SAL_WARN( "connectivity.drivers", "SdbODBC3_SetStatus: SQL_INVALID_HANDLE"); + throw SQLException(); + } + + // Additional Information on the latest ODBC-functioncall available + // SQLError provides this Information. + + SDB_ODBC_CHAR szSqlState[5]; + SQLINTEGER pfNativeError; + SDB_ODBC_CHAR szErrorMessage[SQL_MAX_MESSAGE_LENGTH]; + szErrorMessage[0] = '\0'; + SQLSMALLINT pcbErrorMsg = 0; + + // Information for latest operation: + // when hstmt != SQL_NULL_HSTMT is (Used from SetStatus in SdbCursor, SdbTable, ...), + // then the status of the latest statements will be fetched, without the Status of the last + // statements of this connection [what in this case will probably be the same, but the Reference + // Manual isn't totally clear in this...]. + // corresponding for hdbc. + SQLRETURN n = (*reinterpret_cast<T3SQLGetDiagRec>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetDiagRec)))(_nHandleType,_pContext,1, + szSqlState, + &pfNativeError, + szErrorMessage,sizeof szErrorMessage - 1,&pcbErrorMsg); + OSL_ENSURE(n != SQL_INVALID_HANDLE,"SdbODBC3_SetStatus: SQLError returned SQL_INVALID_HANDLE"); + OSL_ENSURE(n == SQL_SUCCESS || n == SQL_SUCCESS_WITH_INFO || n == SQL_NO_DATA_FOUND || n == SQL_ERROR,"SdbODBC3_SetStatus: SQLError failed"); + + rtl_TextEncoding _nTextEncoding = osl_getThreadTextEncoding(); + // For the Return Code of SQLError see ODBC 2.0 Programmer's Reference Page 287ff + throw SQLException( OUString(reinterpret_cast<char *>(szErrorMessage), pcbErrorMsg, _nTextEncoding), + _xInterface, + OUString(reinterpret_cast<char *>(szSqlState), 5, _nTextEncoding), + pfNativeError, + Any() + ); + +} + +Sequence<sal_Int8> OTools::getBytesValue(const OConnection* _pConnection, + const SQLHANDLE _aStatementHandle, + const sal_Int32 columnIndex, + const SQLSMALLINT _fSqlType, + bool &_bWasNull, + const Reference< XInterface >& _xInterface) +{ + sal_Int8 aCharArray[2048]; + // First try to fetch the data with the little Buffer: + const SQLLEN nMaxLen = sizeof aCharArray; + SQLLEN pcbValue = SQL_NO_TOTAL; + Sequence<sal_Int8> aData; + + OSL_ENSURE( _fSqlType != SQL_CHAR && _fSqlType != SQL_VARCHAR && _fSqlType != SQL_LONGVARCHAR && + _fSqlType != SQL_WCHAR && _fSqlType != SQL_WVARCHAR && _fSqlType != SQL_WLONGVARCHAR, + "connectivity::odbc::OTools::getBytesValue called with character _fSqlType"); + + while (pcbValue == SQL_NO_TOTAL || pcbValue > nMaxLen) + { + OTools::ThrowException(_pConnection, + (*reinterpret_cast<T3SQLGetData>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetData)))( + _aStatementHandle, + static_cast<SQLUSMALLINT>(columnIndex), + _fSqlType, + static_cast<SQLPOINTER>(aCharArray), + nMaxLen, + &pcbValue), + _aStatementHandle,SQL_HANDLE_STMT,_xInterface); + + _bWasNull = pcbValue == SQL_NULL_DATA; + if(_bWasNull) + return Sequence<sal_Int8>(); + + SQLLEN nReadBytes; + // After the SQLGetData that wrote out to aCharArray the last byte of the data, + // pcbValue will not be SQL_NO_TOTAL -> we have a reliable count + if ( (pcbValue == SQL_NO_TOTAL) || (pcbValue >= nMaxLen) ) + { + // we filled the buffer + nReadBytes = nMaxLen; + } + else + { + nReadBytes = pcbValue; + } + const sal_Int32 nLen = aData.getLength(); + aData.realloc(nLen + nReadBytes); + memcpy(aData.getArray() + nLen, aCharArray, nReadBytes); + } + return aData; +} + +OUString OTools::getStringValue(OConnection const * _pConnection, + SQLHANDLE _aStatementHandle, + sal_Int32 columnIndex, + SQLSMALLINT _fSqlType, + bool &_bWasNull, + const Reference< XInterface >& _xInterface, + const rtl_TextEncoding _nTextEncoding) +{ + OUStringBuffer aData; + switch(_fSqlType) + { + case SQL_WVARCHAR: + case SQL_WCHAR: + case SQL_WLONGVARCHAR: + { + SQLWCHAR waCharArray[2048]; + static_assert(sizeof(waCharArray) % sizeof(SQLWCHAR) == 0, "must fit in evenly"); + static_assert(sizeof(SQLWCHAR) == 2 || sizeof(SQLWCHAR) == 4, "must be 2 or 4"); + // Size == number of bytes, Len == number of UTF-16 or UCS4 code units + const SQLLEN nMaxSize = sizeof(waCharArray); + const SQLLEN nMaxLen = sizeof(waCharArray) / sizeof(SQLWCHAR); + static_assert(nMaxLen * sizeof(SQLWCHAR) == nMaxSize, "sizes must match"); + + // read the unicode data + SQLLEN pcbValue = SQL_NO_TOTAL; + while ((pcbValue == SQL_NO_TOTAL ) || (pcbValue >= nMaxSize) ) + { + OTools::ThrowException(_pConnection, + (*reinterpret_cast<T3SQLGetData>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetData)))( + _aStatementHandle, + static_cast<SQLUSMALLINT>(columnIndex), + SQL_C_WCHAR, + &waCharArray, + SQLLEN(nMaxLen)*sizeof(sal_Unicode), + &pcbValue), + _aStatementHandle,SQL_HANDLE_STMT,_xInterface); + _bWasNull = pcbValue == SQL_NULL_DATA; + if(_bWasNull) + return OUString(); + + SQLLEN nReadChars; + OSL_ENSURE( (pcbValue < 0) || (pcbValue % 2 == 0), + "ODBC: SQLGetData of SQL_C_WCHAR returned odd number of bytes"); + if ( (pcbValue == SQL_NO_TOTAL) || (pcbValue >= nMaxSize) ) + { + // we filled the buffer; remove the terminating null character + nReadChars = nMaxLen-1; + if ( waCharArray[nReadChars] != 0) + { + SAL_WARN( "connectivity.drivers", "Buggy ODBC driver? Did not null-terminate (variable length) data!"); + ++nReadChars; + } + } + else + { + nReadChars = pcbValue/sizeof(SQLWCHAR); + } + + appendSQLWCHARs(aData, waCharArray, nReadChars); + } + break; + } + default: + { + char aCharArray[2048]; + // read the unicode data + const SQLLEN nMaxLen = sizeof(aCharArray); + SQLLEN pcbValue = SQL_NO_TOTAL; + + while ((pcbValue == SQL_NO_TOTAL ) || (pcbValue >= nMaxLen) ) + { + OTools::ThrowException(_pConnection, + (*reinterpret_cast<T3SQLGetData>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetData)))( + _aStatementHandle, + static_cast<SQLUSMALLINT>(columnIndex), + SQL_C_CHAR, + &aCharArray, + nMaxLen, + &pcbValue), + _aStatementHandle,SQL_HANDLE_STMT,_xInterface); + _bWasNull = pcbValue == SQL_NULL_DATA; + if(_bWasNull) + return OUString(); + + SQLLEN nReadChars; + if ( (pcbValue == SQL_NO_TOTAL) || (pcbValue >= nMaxLen) ) + { + // we filled the buffer; remove the terminating null character + nReadChars = nMaxLen-1; + if ( aCharArray[nReadChars] != 0) + { + SAL_WARN( "connectivity.drivers", "Buggy ODBC driver? Did not null-terminate (variable length) data!"); + ++nReadChars; + } + } + else + { + nReadChars = pcbValue; + } + + aData.append(OUString(aCharArray, nReadChars, _nTextEncoding)); + + } + break; + } + } + + return aData.makeStringAndClear(); +} + +void OTools::GetInfo(OConnection const * _pConnection, + SQLHANDLE _aConnectionHandle, + SQLUSMALLINT _nInfo, + OUString &_rValue, + const Reference< XInterface >& _xInterface, + rtl_TextEncoding _nTextEncoding) +{ + char aValue[512]; + SQLSMALLINT nValueLen=0; + OTools::ThrowException(_pConnection, + (*reinterpret_cast<T3SQLGetInfo>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(_aConnectionHandle,_nInfo,aValue,(sizeof aValue)-1,&nValueLen), + _aConnectionHandle,SQL_HANDLE_DBC,_xInterface); + + _rValue = OUString(aValue,nValueLen,_nTextEncoding); +} + +void OTools::GetInfo(OConnection const * _pConnection, + SQLHANDLE _aConnectionHandle, + SQLUSMALLINT _nInfo, + sal_Int32 &_rValue, + const Reference< XInterface >& _xInterface) +{ + SQLSMALLINT nValueLen; + _rValue = 0; // in case the driver uses only 16 of the 32 bits (as it does, for example, for SQL_CATALOG_LOCATION) + OTools::ThrowException(_pConnection, + (*reinterpret_cast<T3SQLGetInfo>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(_aConnectionHandle,_nInfo,&_rValue,sizeof _rValue,&nValueLen), + _aConnectionHandle,SQL_HANDLE_DBC,_xInterface); +} + +void OTools::GetInfo(OConnection const * _pConnection, + SQLHANDLE _aConnectionHandle, + SQLUSMALLINT _nInfo, + SQLUINTEGER &_rValue, + const Reference< XInterface >& _xInterface) +{ + SQLSMALLINT nValueLen; + _rValue = 0; // in case the driver uses only 16 of the 32 bits (as it does, for example, for SQL_CATALOG_LOCATION) + OTools::ThrowException(_pConnection, + (*reinterpret_cast<T3SQLGetInfo>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(_aConnectionHandle,_nInfo,&_rValue,sizeof _rValue,&nValueLen), + _aConnectionHandle,SQL_HANDLE_DBC,_xInterface); +} + +void OTools::GetInfo(OConnection const * _pConnection, + SQLHANDLE _aConnectionHandle, + SQLUSMALLINT _nInfo, + SQLUSMALLINT &_rValue, + const Reference< XInterface >& _xInterface) +{ + SQLSMALLINT nValueLen; + _rValue = 0; // in case the driver uses only 16 of the 32 bits (as it does, for example, for SQL_CATALOG_LOCATION) + OTools::ThrowException(_pConnection, + (*reinterpret_cast<T3SQLGetInfo>(_pConnection->getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(_aConnectionHandle,_nInfo,&_rValue,sizeof _rValue,&nValueLen), + _aConnectionHandle,SQL_HANDLE_DBC,_xInterface); +} + +sal_Int32 OTools::MapOdbcType2Jdbc(SQLSMALLINT _nType) +{ + sal_Int32 nValue = DataType::VARCHAR; + switch(_nType) + { + case SQL_BIT: + nValue = DataType::BIT; + break; + case SQL_TINYINT: + nValue = DataType::TINYINT; + break; + case SQL_SMALLINT: + nValue = DataType::SMALLINT; + break; + case SQL_INTEGER: + nValue = DataType::INTEGER; + break; + case SQL_BIGINT: + nValue = DataType::BIGINT; + break; + case SQL_FLOAT: + nValue = DataType::FLOAT; + break; + case SQL_REAL: + nValue = DataType::REAL; + break; + case SQL_DOUBLE: + nValue = DataType::DOUBLE; + break; + case SQL_NUMERIC: + nValue = DataType::NUMERIC; + break; + case SQL_DECIMAL: + nValue = DataType::DECIMAL; + break; + case SQL_WCHAR: + case SQL_CHAR: + nValue = DataType::CHAR; + break; + case SQL_WVARCHAR: + case SQL_VARCHAR: + nValue = DataType::VARCHAR; + break; + case SQL_WLONGVARCHAR: + case SQL_LONGVARCHAR: + nValue = DataType::LONGVARCHAR; + break; + case SQL_TYPE_DATE: + case SQL_DATE: + nValue = DataType::DATE; + break; + case SQL_TYPE_TIME: + case SQL_TIME: + nValue = DataType::TIME; + break; + case SQL_TYPE_TIMESTAMP: + case SQL_TIMESTAMP: + nValue = DataType::TIMESTAMP; + break; + case SQL_BINARY: + nValue = DataType::BINARY; + break; + case SQL_VARBINARY: + case SQL_GUID: + nValue = DataType::VARBINARY; + break; + case SQL_LONGVARBINARY: + nValue = DataType::LONGVARBINARY; + break; + default: + OSL_FAIL("Invalid type"); + } + return nValue; +} + +// jdbcTypeToOdbc +// Convert the JDBC SQL type to the correct ODBC type + +SQLSMALLINT OTools::jdbcTypeToOdbc(sal_Int32 jdbcType) +{ + // For the most part, JDBC types match ODBC types. We'll + // just convert the ones that we know are different + + sal_Int32 odbcType = jdbcType; + + switch (jdbcType) + { + case DataType::DATE: + odbcType = SQL_DATE; + break; + case DataType::TIME: + odbcType = SQL_TIME; + break; + case DataType::TIMESTAMP: + odbcType = SQL_TIMESTAMP; + break; + // ODBC doesn't have any notion of CLOB or BLOB + case DataType::CLOB: + odbcType = SQL_LONGVARCHAR; + break; + case DataType::BLOB: + odbcType = SQL_LONGVARBINARY; + break; + } + + return odbcType; +} + +void OTools::getBindTypes(bool _bUseWChar, + bool _bUseOldTimeDate, + SQLSMALLINT _nOdbcType, + SQLSMALLINT& fCType, + SQLSMALLINT& fSqlType + ) +{ + switch(_nOdbcType) + { + case SQL_CHAR: if(_bUseWChar) + { + fCType = SQL_C_WCHAR; + fSqlType = SQL_WCHAR; + } + else + { + fCType = SQL_C_CHAR; + fSqlType = SQL_CHAR; + } + break; + case SQL_VARCHAR: if(_bUseWChar) + { + fCType = SQL_C_WCHAR; + fSqlType = SQL_WVARCHAR; + } + else + { + fCType = SQL_C_CHAR; + fSqlType = SQL_VARCHAR; + } + break; + case SQL_LONGVARCHAR: if(_bUseWChar) + { + fCType = SQL_C_WCHAR; + fSqlType = SQL_WLONGVARCHAR; + } + else + { + fCType = SQL_C_CHAR; + fSqlType = SQL_LONGVARCHAR; + } + break; + case SQL_DECIMAL: fCType = _bUseWChar ? SQL_C_WCHAR : SQL_C_CHAR; + fSqlType = SQL_DECIMAL; break; + case SQL_NUMERIC: fCType = _bUseWChar ? SQL_C_WCHAR : SQL_C_CHAR; + fSqlType = SQL_NUMERIC; break; + case SQL_BIT: fCType = SQL_C_TINYINT; + fSqlType = SQL_INTEGER; break; + case SQL_TINYINT: fCType = SQL_C_TINYINT; + fSqlType = SQL_TINYINT; break; + case SQL_SMALLINT: fCType = SQL_C_SHORT; + fSqlType = SQL_SMALLINT; break; + case SQL_INTEGER: fCType = SQL_C_LONG; + fSqlType = SQL_INTEGER; break; + case SQL_BIGINT: fCType = SQL_C_SBIGINT; + fSqlType = SQL_BIGINT; break; + case SQL_FLOAT: fCType = SQL_C_FLOAT; + fSqlType = SQL_FLOAT; break; + case SQL_REAL: fCType = SQL_C_DOUBLE; + fSqlType = SQL_REAL; break; + case SQL_DOUBLE: fCType = SQL_C_DOUBLE; + fSqlType = SQL_DOUBLE; break; + case SQL_BINARY: fCType = SQL_C_BINARY; + fSqlType = SQL_BINARY; break; + case SQL_VARBINARY: + fCType = SQL_C_BINARY; + fSqlType = SQL_VARBINARY; break; + case SQL_LONGVARBINARY: fCType = SQL_C_BINARY; + fSqlType = SQL_LONGVARBINARY; break; + case SQL_DATE: + if(_bUseOldTimeDate) + { + fCType = SQL_C_DATE; + fSqlType = SQL_DATE; + } + else + { + fCType = SQL_C_TYPE_DATE; + fSqlType = SQL_TYPE_DATE; + } + break; + case SQL_TIME: + if(_bUseOldTimeDate) + { + fCType = SQL_C_TIME; + fSqlType = SQL_TIME; + } + else + { + fCType = SQL_C_TYPE_TIME; + fSqlType = SQL_TYPE_TIME; + } + break; + case SQL_TIMESTAMP: + if(_bUseOldTimeDate) + { + fCType = SQL_C_TIMESTAMP; + fSqlType = SQL_TIMESTAMP; + } + else + { + fCType = SQL_C_TYPE_TIMESTAMP; + fSqlType = SQL_TYPE_TIMESTAMP; + } + break; + default: fCType = SQL_C_BINARY; + fSqlType = SQL_LONGVARBINARY; break; + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/odbc/odbc.component b/connectivity/source/drivers/odbc/odbc.component new file mode 100644 index 000000000..4fa186ea2 --- /dev/null +++ b/connectivity/source/drivers/odbc/odbc.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="odbc" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.ODBCDriver"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/odbc/oservices.cxx b/connectivity/source/drivers/odbc/oservices.cxx new file mode 100644 index 000000000..6461f8dde --- /dev/null +++ b/connectivity/source/drivers/odbc/oservices.cxx @@ -0,0 +1,108 @@ +/* -*- 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 "ORealDriver.hxx" +#include <odbc/ODriver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace connectivity::odbc; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::lang::XSingleServiceFactory; +using ::com::sun::star::lang::XMultiServiceFactory; + +typedef Reference< XSingleServiceFactory > (*createFactoryFunc) + ( + const Reference< XMultiServiceFactory > & rServiceManager, + const OUString & rComponentName, + ::cppu::ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount* + ); + +namespace { + +struct ProviderRequest +{ + Reference< XSingleServiceFactory > xRet; + Reference< XMultiServiceFactory > const xServiceManager; + OUString const sImplementationName; + + ProviderRequest( + void* pServiceManager, + char const* pImplementationName + ) + : xServiceManager(static_cast<XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER( + const OUString& Implname, + const Sequence< OUString > & Services, + ::cppu::ComponentInstantiation Factory, + createFactoryFunc creator + ) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator( xServiceManager, sImplementationName,Factory, Services,nullptr); + } + catch(...) + { + } + } + return xRet.is(); + } + + void* getProvider() const { return xRet.get(); } +}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* odbc_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager,pImplementationName); + + aReq.CREATE_PROVIDER( + ODBCDriver::getImplementationName_Static(), + ODBCDriver::getSupportedServiceNames_Static(), + ODBCDriver_CreateInstance, ::cppu::createSingleFactory) + ; + + if(aReq.xRet.is()) + aReq.xRet->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component b/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component new file mode 100644 index 000000000..89164b6e7 --- /dev/null +++ b/connectivity/source/drivers/postgresql/postgresql-sdbc-impl.component @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="postgresql_sdbc_impl" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.connectivity.pq.Connection.noext"> + <service name="com.sun.star.sdbc.Connection"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/postgresql/postgresql-sdbc.component b/connectivity/source/drivers/postgresql/postgresql-sdbc.component new file mode 100644 index 000000000..ebb200954 --- /dev/null +++ b/connectivity/source/drivers/postgresql/postgresql-sdbc.component @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="postgresql_sdbc" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="org.openoffice.comp.connectivity.pq.Driver.noext"> + <service name="com.sun.star.sdbc.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/drivers/postgresql/pq_array.cxx b/connectivity/source/drivers/postgresql/pq_array.cxx new file mode 100644 index 000000000..5ae646f23 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_array.cxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <comphelper/sequence.hxx> + + +#include "pq_array.hxx" +#include "pq_statics.hxx" +#include "pq_sequenceresultset.hxx" + + +using com::sun::star::sdbc::SQLException; +using com::sun::star::uno::Any; + +using com::sun::star::uno::Sequence; +namespace pq_sdbc_driver +{ + + +OUString Array::getBaseTypeName( ) +{ + return "varchar"; +} + +sal_Int32 Array::getBaseType( ) +{ + return css::sdbc::DataType::VARCHAR; +} + +css::uno::Sequence< css::uno::Any > Array::getArray( + const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ ) +{ + return comphelper::containerToSequence(m_data); +} + +css::uno::Sequence< css::uno::Any > Array::getArrayAtIndex( + sal_Int32 index, + sal_Int32 count, + const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ ) +{ + checkRange( index, count ); + return Sequence< Any > ( &m_data[index-1], count ); +} + +css::uno::Reference< css::sdbc::XResultSet > Array::getResultSet( + const css::uno::Reference< css::container::XNameAccess >& typeMap ) +{ + return getResultSetAtIndex( 0 , m_data.size() , typeMap ); +} + +css::uno::Reference< css::sdbc::XResultSet > Array::getResultSetAtIndex( + sal_Int32 index, + sal_Int32 count, + const css::uno::Reference< css::container::XNameAccess >& /* typeMap */ ) +{ + checkRange( index, count ); + std::vector< std::vector< Any > > ret( count ); + + for( int i = 0 ; i < count ; i ++ ) + { + std::vector< Any > row( 2 ); + row[0] <<= static_cast<sal_Int32>( i + index ); + row[1] = m_data[i+index-1]; + ret[i] = row; + } + + return new SequenceResultSet( + m_xMutex, m_owner, getStatics().resultSetArrayColumnNames, ret, m_tc ); +} + + +void Array::checkRange( sal_Int32 index, sal_Int32 count ) +{ + if( index >= 1 && index -1 + count <= static_cast<sal_Int32>(m_data.size()) ) + return; + throw SQLException( + "Array::getArrayAtIndex(): allowed range for index + count " + + OUString::number( m_data.size() ) + + ", got " + OUString::number( index ) + + " + " + OUString::number( count ), + *this, OUString(), 1, Any()); + +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_array.hxx b/connectivity/source/drivers/postgresql/pq_array.hxx new file mode 100644 index 000000000..c0ed6aa97 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_array.hxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_ARRAY_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_ARRAY_HXX +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/sdbc/XArray.hpp> + +#include "pq_connection.hxx" +#include <vector> + +namespace pq_sdbc_driver +{ + +class Array : public cppu::WeakImplHelper< css::sdbc::XArray > +{ + std::vector< css::uno::Any > m_data; + css::uno::Reference< css::uno::XInterface > m_owner; + css::uno::Reference< css::script::XTypeConverter > m_tc; + rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + +public: + Array( + const rtl::Reference< comphelper::RefCountedMutex > & mutex, + const std::vector< css::uno::Any > & data, + const css::uno::Reference< css::uno::XInterface > & owner, + const css::uno::Reference< css::script::XTypeConverter > &tc) : + m_data( data ), + m_owner( owner ), + m_tc( tc ), + m_xMutex( mutex ) + {} + +public: // XArray + + // Methods + virtual OUString SAL_CALL getBaseTypeName( ) override; + + virtual sal_Int32 SAL_CALL getBaseType( ) override; + + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArray( + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArrayAtIndex( + sal_Int32 index, + sal_Int32 count, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + getResultSet( + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSetAtIndex( + sal_Int32 index, + sal_Int32 count, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + +private: + void checkRange( sal_Int32 index, sal_Int32 count ); +}; + + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_baseresultset.cxx b/connectivity/source/drivers/postgresql/pq_baseresultset.cxx new file mode 100644 index 000000000..8fc7140e4 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_baseresultset.cxx @@ -0,0 +1,613 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <comphelper/sequence.hxx> + +#include "pq_tools.hxx" +#include "pq_array.hxx" +#include "pq_baseresultset.hxx" + +#include <com/sun/star/script/CannotConvertException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <connectivity/dbconversion.hxx> + +using osl::MutexGuard; + + +using com::sun::star::beans::XPropertySetInfo; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; + +using com::sun::star::lang::IllegalArgumentException; + +using com::sun::star::sdbc::SQLException; + + +using com::sun::star::beans::Property; + +using namespace dbtools; + +namespace pq_sdbc_driver +{ +static ::cppu::IPropertyArrayHelper & getResultSetPropertyArrayHelper() +{ + // LEM TODO: this needs to be kept in sync with other, e.g. pq_statics.css:508 + // Should really share! + // At least use for the handles the #define'd values in .hxx file... + static ::cppu::OPropertyArrayHelper arrayHelper( + Sequence<Property>{ + Property( + "CursorName", 0, + ::cppu::UnoType<OUString>::get() , 0 ), + Property( + "EscapeProcessing", 1, + cppu::UnoType<bool>::get() , 0 ), + Property( + "FetchDirection", 2, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "FetchSize", 3, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "IsBookmarkable", 4, + cppu::UnoType<bool>::get() , 0 ), + Property( + "ResultSetConcurrency", 5, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetType", 6, + ::cppu::UnoType<sal_Int32>::get() , 0 )}, + true ); + return arrayHelper; +} + +BaseResultSet::BaseResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< XInterface > & owner, + sal_Int32 rowCount, + sal_Int32 colCount, + const Reference< css::script::XTypeConverter > & tc ) + : BaseResultSet_BASE( refMutex->GetMutex() ) + , OPropertySetHelper( BaseResultSet_BASE::rBHelper ) + , m_owner( owner ) + , m_tc( tc ) + , m_xMutex( refMutex ) + , m_row( -1 ) + , m_rowCount( rowCount ) + , m_fieldCount( colCount ) + , m_wasNull(false) +{ +} + +// LEM TODO: refMutex->GetMutex() should live longer than OComponentHelper, +// but calling OComponentHelper::dispose explicitly here calls +// BaseResultSet::~BaseResultSet in an infinite loop :( +BaseResultSet::~BaseResultSet() +{ +} + +Any BaseResultSet::queryInterface( const Type & rType ) +{ + Any aRet = BaseResultSet_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + +// void BaseResultSet::close( ) throw (SQLException, RuntimeException) +// { +// Reference< XInterface > owner; +// { +// ResultSetGuard guard(*this); +// if( m_result ) +// { +// PQclear(m_result ); +// m_result = 0; +// m_row = -1; +// } +// owner = m_owner; +// m_owner.clear(); +// } +// } + +Sequence<Type > BaseResultSet::getTypes() +{ + static Sequence< Type > collection( + ::comphelper::concatSequences( + OPropertySetHelper::getTypes(), + BaseResultSet_BASE::getTypes())); + return collection; +} + +Sequence< sal_Int8> BaseResultSet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// Reference< XResultSetMetaData > BaseResultSet::getMetaData( ) throw (SQLException, RuntimeException) +// { +// ResultSetGuard guard(*this); +// checkClosed(); +// return new ResultSetMetaData( m_xMutex, this, &m_result ); +// } + +sal_Bool BaseResultSet::next( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + m_row ++; + return m_row < m_rowCount; +} + +sal_Bool BaseResultSet::isBeforeFirst( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row == -1; +} + +sal_Bool BaseResultSet::isAfterLast( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row >= m_rowCount; +} + +sal_Bool BaseResultSet::isFirst( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row == 0 && m_rowCount; +} + +sal_Bool BaseResultSet::isLast( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row >= 0 && m_row + 1 == m_rowCount; +} + +void BaseResultSet::beforeFirst( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + m_row = -1; +} + +void BaseResultSet::afterLast( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + m_row = m_rowCount; +} + +sal_Bool BaseResultSet::first( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + bool bRet = ( m_rowCount > 0 ); + if( bRet ) + m_row = 0; + return bRet; +} + +sal_Bool BaseResultSet::last( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + bool bRet = ( m_rowCount > 0 ); + if( bRet ) + m_row = m_rowCount -1; + return bRet; +} + +sal_Int32 BaseResultSet::getRow( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_row +1; +} + +sal_Bool BaseResultSet::absolute( sal_Int32 row ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + if( row > 0 ) + { + m_row = row -1; + if( m_row > m_rowCount ) + m_row = m_rowCount; + } + else + { + m_row = m_rowCount + row; + if( m_row < -1 ) + m_row = -1; + } + return true; +} + +sal_Bool BaseResultSet::relative( sal_Int32 rows ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + m_row += rows; + + if( m_row > m_rowCount ) + m_row = m_rowCount; + else if ( m_row < -1 ) + m_row = -1; + return true; +} + +sal_Bool BaseResultSet::previous( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + bool bRet = ( m_row != -1 ); + if( bRet ) + m_row --; + return bRet; +} + +void BaseResultSet::refreshRow( ) +{ + // TODO: not supported for now +} + +sal_Bool BaseResultSet::rowUpdated( ) +{ + return false; +} + +sal_Bool BaseResultSet::rowInserted( ) +{ + return false; +} + +sal_Bool BaseResultSet::rowDeleted( ) +{ + return false; +} + +Reference< XInterface > BaseResultSet::getStatement() +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return m_owner; +} + + +//----------------- XRow interface ---------------------------------------------------- + +sal_Bool BaseResultSet::wasNull( ) +{ + return m_wasNull; +} + +Any BaseResultSet::convertTo( const Any & val , const Type & type ) +{ + Any aRet; + try + { + aRet = m_tc->convertTo( val , type ); + } + catch( css::lang::IllegalArgumentException & ) + {} + catch( css::script::CannotConvertException & ) + {} + return aRet; +} + +sal_Bool BaseResultSet::getBoolean( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + + OUString str = getString( columnIndex ); + + if( str.getLength() > 0 ) + { + switch(str[0]) + { + case '1': + case 't': + case 'T': + case 'y': + case 'Y': + + return true; + } + } + return false; +} + +sal_Int8 BaseResultSet::getByte( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + sal_Int8 b = 0; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(b)>::get()) >>= b; + return b; +} + +sal_Int16 BaseResultSet::getShort( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + sal_Int16 i = 0; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i; + return i; +} + +OUString BaseResultSet::getString( sal_Int32 columnIndex ) +{ + MutexGuard guard(m_xMutex->GetMutex()); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + OUString ret; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(ret)>::get() ) >>= ret; +// printf( "BaseResultSet::getString() %s\n" , OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ).getStr() ); + return ret; +} + +sal_Int32 BaseResultSet::getInt( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + sal_Int32 i = 0; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i; + return i; +} + +sal_Int64 BaseResultSet::getLong( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + sal_Int64 i = 0; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(i)>::get()) >>= i; + return i; +} + +float BaseResultSet::getFloat( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + float f = 0.; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(f)>::get()) >>= f; + return f; +} + +double BaseResultSet::getDouble( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + double d = 0.; + convertTo( getValue( columnIndex ), cppu::UnoType<decltype(d)>::get()) >>= d; + return d; +} + +Sequence< sal_Int8 > BaseResultSet::getBytes( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( columnIndex ); + checkRowIndex(); + + Sequence< sal_Int8 > ret; + OUString ustr; + if( ! (getValue( columnIndex ) >>= ustr) ) + m_wasNull = true; + else + { + // if this is a binary, it must contain escaped data ! + OString val = OUStringToOString( ustr, RTL_TEXTENCODING_ASCII_US ); + + size_t length; + char * res = reinterpret_cast<char*>(PQunescapeBytea( reinterpret_cast<unsigned char const *>(val.getStr()), &length)); + ret = Sequence< sal_Int8 > ( reinterpret_cast<sal_Int8*>(res), length ); + if( res ) + free( res ); + } + return ret; +} + + +css::util::Date BaseResultSet::getDate( sal_Int32 columnIndex ) +{ + return DBTypeConversion::toDate( getString( columnIndex ) ); +} + +css::util::Time BaseResultSet::getTime( sal_Int32 columnIndex ) +{ + return DBTypeConversion::toTime( getString( columnIndex ) ); +} + +css::util::DateTime BaseResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + return DBTypeConversion::toDateTime( getString( columnIndex ) ); +} + + // LEM TODO: these look like they are missing an actual implementation +Reference< css::io::XInputStream > BaseResultSet::getBinaryStream( sal_Int32 /* columnIndex */ ) +{ + return nullptr; +} + +Reference< css::io::XInputStream > BaseResultSet::getCharacterStream( sal_Int32 /* columnIndex */ ) +{ + return nullptr; +} + +Any BaseResultSet::getObject( + sal_Int32 /* columnIndex */, + const Reference< css::container::XNameAccess >& /* typeMap */ ) +{ + return Any(); +} + +Reference< css::sdbc::XRef > BaseResultSet::getRef( sal_Int32 /* columnIndex */ ) +{ + return Reference< css::sdbc::XRef > (); +} + +Reference< css::sdbc::XBlob > BaseResultSet::getBlob( sal_Int32 /* columnIndex */ ) +{ + return Reference< css::sdbc::XBlob > (); +} + +Reference< css::sdbc::XClob > BaseResultSet::getClob( sal_Int32 /* columnIndex */ ) +{ + return Reference< css::sdbc::XClob > (); +} + +Reference< css::sdbc::XArray > BaseResultSet::getArray( sal_Int32 columnIndex ) +{ + return new Array( m_xMutex, parseArray( getString( columnIndex ) ), *this, m_tc ); +} + +::cppu::IPropertyArrayHelper & BaseResultSet::getInfoHelper() +{ + return getResultSetPropertyArrayHelper(); +} + +sal_Bool BaseResultSet::convertFastPropertyValue( + Any & /* rConvertedValue */, Any & /* rOldValue */, sal_Int32 nHandle, const Any& rValue ) +{ + bool bRet; + switch( nHandle ) + { + case BASERESULTSET_CURSOR_NAME: + { + OUString val; + bRet = ( rValue >>= val ); + m_props[nHandle] <<= val; + break; + } + case BASERESULTSET_ESCAPE_PROCESSING: + case BASERESULTSET_IS_BOOKMARKABLE: + { + bool val(false); + bRet = ( rValue >>= val ); + m_props[nHandle] <<= val; + break; + } + case BASERESULTSET_FETCH_DIRECTION: + case BASERESULTSET_FETCH_SIZE: + case BASERESULTSET_RESULT_SET_CONCURRENCY: + case BASERESULTSET_RESULT_SET_TYPE: + { + sal_Int32 val; + bRet = ( rValue >>= val ); + m_props[nHandle] <<= val; + break; + } + default: + { + throw IllegalArgumentException( + "pq_resultset: Invalid property handle (" + OUString::number( nHandle ) + ")", + *this, 2 ); + } + } + return bRet; +} + + +void BaseResultSet::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle,const Any& rValue ) +{ + m_props[nHandle] = rValue; +} + +void BaseResultSet::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + rValue = m_props[nHandle]; +} + +Reference < XPropertySetInfo > BaseResultSet::getPropertySetInfo() +{ + return OPropertySetHelper::createPropertySetInfo( getResultSetPropertyArrayHelper() ); +} + +void BaseResultSet::disposing() +{ + close(); +} + +void BaseResultSet::checkColumnIndex(sal_Int32 index ) +{ + if( index < 1 || index > m_fieldCount ) + { + throw SQLException( + "pq_resultset: index out of range (" + + OUString::number( index ) + + ", allowed range is 1 to " + OUString::number( m_fieldCount ) + + ")", + *this, OUString(), 1, Any() ); + } + +} + +void BaseResultSet::checkRowIndex() +{ + if( m_row < 0 || m_row >= m_rowCount ) + { + throw SQLException( + "pq_baseresultset: row index out of range, allowed is 0 to " + OUString::number( m_rowCount -1 ) + + ", got " + OUString::number( m_row ), + *this, OUString(),1, Any() ); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_baseresultset.hxx b/connectivity/source/drivers/postgresql/pq_baseresultset.hxx new file mode 100644 index 000000000..27ec2e62a --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_baseresultset.hxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_BASERESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_BASERESULTSET_HXX + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> + +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include "pq_connection.hxx" + +namespace pq_sdbc_driver +{ + +static const sal_Int32 BASERESULTSET_CURSOR_NAME = 0; +static const sal_Int32 BASERESULTSET_ESCAPE_PROCESSING = 1; +static const sal_Int32 BASERESULTSET_FETCH_DIRECTION = 2; +static const sal_Int32 BASERESULTSET_FETCH_SIZE = 3; +static const sal_Int32 BASERESULTSET_IS_BOOKMARKABLE = 4; +static const sal_Int32 BASERESULTSET_RESULT_SET_CONCURRENCY = 5; +static const sal_Int32 BASERESULTSET_RESULT_SET_TYPE = 6; + +#define BASERESULTSET_SIZE 7 + +typedef ::cppu::WeakComponentImplHelper< css::sdbc::XCloseable, + css::sdbc::XResultSetMetaDataSupplier, + css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XColumnLocate + > BaseResultSet_BASE; +class BaseResultSet : public BaseResultSet_BASE, + public cppu::OPropertySetHelper +{ +protected: + css::uno::Any m_props[BASERESULTSET_SIZE]; + css::uno::Reference< css::uno::XInterface > m_owner; + css::uno::Reference< css::script::XTypeConverter > m_tc; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + sal_Int32 m_row; + sal_Int32 m_rowCount; + sal_Int32 m_fieldCount; + bool m_wasNull; + +protected: + /** mutex should be locked before called + + @throws css::sdbc::SQLException + @throws css::uno::RuntimeException + */ + virtual void checkClosed() = 0; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex( sal_Int32 index ); + void checkRowIndex(); + + virtual css::uno::Any getValue( sal_Int32 columnIndex ) = 0; + css::uno::Any convertTo( + const css::uno::Any &str, const css::uno::Type &type ); + +protected: + BaseResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + sal_Int32 rowCount, + sal_Int32 columnCount, + const css::uno::Reference< css::script::XTypeConverter > &tc ); + virtual ~BaseResultSet() override; + +public: // XInterface + virtual void SAL_CALL acquire() throw() override { BaseResultSet_BASE::acquire(); } + virtual void SAL_CALL release() throw() override { BaseResultSet_BASE::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XCloseable +// virtual void SAL_CALL close( ) +// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XResultSetMetaDataSupplier +// virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) +// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0; + +public: // XResultSet + // Methods + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement() override; + + +public: // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( + sal_Int32 columnIndex, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + +public: // XColumnLocate +// virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) +// throw (css::sdbc::SQLException, css::uno::RuntimeException) = 0; + +public: // OPropertySetHelper + virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + + void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + // XPropertySet + css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + +public: // OComponentHelper + virtual void SAL_CALL disposing() override; + + +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_connection.cxx b/connectivity/source/drivers/postgresql/pq_connection.cxx new file mode 100644 index 000000000..66c30c893 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_connection.cxx @@ -0,0 +1,609 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <vector> +#include <time.h> +#include <string.h> + +#include <memory> + +#include "pq_connection.hxx" +#include "pq_statement.hxx" +#include "pq_preparedstatement.hxx" +#include "pq_databasemetadata.hxx" +#include "pq_xtables.hxx" +#include "pq_xviews.hxx" +#include "pq_xusers.hxx" + +#include <rtl/uuid.h> +#include <rtl/bootstrap.hxx> +#include <sal/log.hxx> +#include <o3tl/enumarray.hxx> +#include <osl/module.h> + +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/script/Converter.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +using osl::MutexGuard; + +using com::sun::star::container::XNameAccess; + +using com::sun::star::lang::XComponent; +using com::sun::star::lang::IllegalArgumentException; + +using com::sun::star::script::Converter; +using com::sun::star::script::XTypeConverter; + +using com::sun::star::uno::RuntimeException; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::Any; + +using com::sun::star::beans::PropertyValue; + +using com::sun::star::sdbc::XCloseable; +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XPreparedStatement; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XDatabaseMetaData; + +namespace pq_sdbc_driver +{ + +namespace { + +// Helper class for statement lifetime management +class ClosableReference : public cppu::WeakImplHelper< css::uno::XReference > +{ + rtl::Reference<Connection> m_conn; + ::rtl::ByteSequence m_id; +public: + ClosableReference( const ::rtl::ByteSequence & id , Connection *that ) + : m_conn( that ), m_id( id ) + { + } + + virtual void SAL_CALL dispose() override + { + if( m_conn.is() ) + { + m_conn->removeFromWeakMap(m_id); + m_conn.clear(); + } + } +}; + +} + +static OUString ConnectionGetImplementationName() +{ + return "org.openoffice.comp.connectivity.pq.Connection.noext"; +} +static css::uno::Sequence<OUString> ConnectionGetSupportedServiceNames() +{ + return Sequence< OUString > { "com.sun.star.sdbc.Connection" }; +} + +Connection::Connection( + const rtl::Reference< comphelper::RefCountedMutex > &refMutex, + const css::uno::Reference< css::uno::XComponentContext > & ctx ) + : ConnectionBase( refMutex->GetMutex() ), + m_ctx( ctx ) , + m_xMutex( refMutex ) +{ +} + +Connection::~Connection() +{ + if( m_settings.pConnection ) + { + PQfinish( m_settings.pConnection ); + m_settings.pConnection = nullptr; + } +} +typedef std::vector< css::uno::Reference< css::sdbc::XCloseable > > CloseableVector; + +typedef std::vector< css::uno::Reference< css::lang::XComponent > > DisposeableVector; + +void Connection::close() +{ + CloseableVector vectorCloseable; + DisposeableVector vectorDispose; + { + MutexGuard guard( m_xMutex->GetMutex() ); + // silently ignore, if the connection has been closed already + if( m_settings.pConnection ) + { + SAL_INFO("connectivity.postgresql", "closing connection"); + PQfinish( m_settings.pConnection ); + m_settings.pConnection = nullptr; + } + + vectorDispose.push_back( Reference< XComponent > ( m_settings.users, UNO_QUERY ) ); + vectorDispose.push_back( Reference< XComponent > ( m_settings.tables , UNO_QUERY ) ); + vectorDispose.push_back( Reference< XComponent > ( m_meta, UNO_QUERY ) ); + m_meta.clear(); + m_settings.tables.clear(); + m_settings.users.clear(); + + for (auto const& statement : m_myStatements) + { + Reference< XCloseable > r = statement.second; + if( r.is() ) + vectorCloseable.push_back( r ); + } + } + + // close all created statements + for (auto const& elem : vectorCloseable) + elem->close(); + + // close all created statements + for (auto const& elem : vectorDispose) + { + if( elem.is() ) + elem->dispose(); + } +} + + +void Connection::removeFromWeakMap( const ::rtl::ByteSequence & id ) +{ + // shrink the list ! + MutexGuard guard( m_xMutex->GetMutex() ); + WeakHashMap::iterator ii = m_myStatements.find( id ); + if( ii != m_myStatements.end() ) + m_myStatements.erase( ii ); +} + +Reference< XStatement > Connection::createStatement() +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + + Statement *stmt = new Statement( m_xMutex, this , &m_settings ); + Reference< XStatement > ret( stmt ); + ::rtl::ByteSequence id( 16 ); + rtl_createUuid( reinterpret_cast<sal_uInt8*>(id.getArray()), nullptr, false ); + m_myStatements[ id ] = Reference< XCloseable > ( stmt ); + stmt->queryAdapter()->addReference( new ClosableReference( id, this ) ); + return ret; +} + +Reference< XPreparedStatement > Connection::prepareStatement( const OUString& sql ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + + OString byteSql = OUStringToOString( sql, ConnectionSettings::encoding ); + PreparedStatement *stmt = new PreparedStatement( m_xMutex, this, &m_settings, byteSql ); + Reference< XPreparedStatement > ret = stmt; + + ::rtl::ByteSequence id( 16 ); + rtl_createUuid( reinterpret_cast<sal_uInt8*>(id.getArray()), nullptr, false ); + m_myStatements[ id ] = Reference< XCloseable > ( stmt ); + stmt->queryAdapter()->addReference( new ClosableReference( id, this ) ); + return ret; +} + +Reference< XPreparedStatement > Connection::prepareCall( const OUString& ) +{ + throw SQLException( + "pq_driver: Callable statements not supported", + Reference< XInterface > (), OUString() , 1, Any() ); +} + + +OUString Connection::nativeSQL( const OUString& sql ) +{ + return sql; +} + +void Connection::setAutoCommit( sal_Bool ) +{ + // UNSUPPORTED +} + +sal_Bool Connection::getAutoCommit() +{ + // UNSUPPORTED + return true; +} + +void Connection::commit() +{ + // UNSUPPORTED +} + +void Connection::rollback() +{ + // UNSUPPORTED +} + +sal_Bool Connection::isClosed() +{ + return m_settings.pConnection == nullptr; +} + +Reference< XDatabaseMetaData > Connection::getMetaData() +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + if( ! m_meta.is() ) + m_meta = new DatabaseMetaData( m_xMutex, this, &m_settings ); + return m_meta; +} + +void Connection::setReadOnly( sal_Bool ) +{ + // UNSUPPORTED + +} + +sal_Bool Connection::isReadOnly() +{ + // UNSUPPORTED + return false; +} + +void Connection::setCatalog( const OUString& ) +{ + // UNSUPPORTED +} + +OUString Connection::getCatalog() +{ + MutexGuard guard( m_xMutex->GetMutex() ); + if( m_settings.pConnection == nullptr ) + { + throw SQLException( "pq_connection: connection is closed", *this, + OUString(), 1, Any() ); + } + char * p = PQdb(m_settings.pConnection ); + return OUString( p, strlen(p) , ConnectionSettings::encoding ); +} + +void Connection::setTransactionIsolation( sal_Int32 ) +{ + // UNSUPPORTED +} + +sal_Int32 Connection::getTransactionIsolation() +{ + // UNSUPPORTED + return 0; +} + +Reference< XNameAccess > Connection::getTypeMap() +{ + Reference< XNameAccess > t; + { + MutexGuard guard( m_xMutex->GetMutex() ); + t = m_typeMap; + } + return t; +} + +void Connection::setTypeMap( const Reference< XNameAccess >& typeMap ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + m_typeMap = typeMap; +} +Any Connection::getWarnings() +{ + return Any(); +} + +void Connection::clearWarnings() +{ +} + +namespace { + +class cstr_vector +{ + std::vector<char*> values; + std::vector<bool> acquired; +public: + cstr_vector () : values(), acquired() { values.reserve(8); acquired.reserve(8); } + ~cstr_vector () + { + OSL_ENSURE(values.size() == acquired.size(), "pq_connection: cstr_vector values and acquired size mismatch"); + std::vector<bool>::const_iterator pa = acquired.begin(); + for( const auto& v : values ) + { + if (*pa) + free(v); + ++pa; + } + } + void push_back(const char* s, __sal_NoAcquire) + { + values.push_back(const_cast<char*>(s)); + acquired.push_back(false); + } + void push_back(char* s) + { + values.push_back(s); + acquired.push_back(true); + } + // This const_cast is there for compatibility with PostgreSQL <= 9.1; + // PostgreSQL >= 9.2 has the right const qualifiers in the headers + // for a return type of "char const*const*". + char const** c_array() const { return const_cast <const char**>(values.data()); } +}; + +} + +static void properties2arrays( const Sequence< PropertyValue > & args, + const Reference< XTypeConverter> &tc, + rtl_TextEncoding enc, + cstr_vector &keywords, + cstr_vector &values) +{ + // LEM TODO: can we just blindly take all properties? + // I.e. they are prefiltered to have only relevant ones? + // Else, at least support all keywords from + // http://www.postgresql.org/docs/9.0/interactive/libpq-connect.html + + static const char* keyword_list[] = { + "password", + "user", + "port", + "dbname", + "connect_timeout", + "options", + "requiressl" + }; + + for( PropertyValue const & prop : args ) + { + bool append = false; + for(const char* j : keyword_list) + { + if( prop.Name.equalsIgnoreAsciiCaseAscii( j )) + { + keywords.push_back( j, SAL_NO_ACQUIRE ); + append = true; + break; + } + } + + if( append ) + { + OUString value; + tc->convertTo( prop.Value, cppu::UnoType<decltype(value)>::get() ) >>= value; + char *v = strdup(OUStringToOString(value, enc).getStr()); + values.push_back ( v ); + } + else + { + // ignore for now + SAL_WARN("connectivity.postgresql", "sdbc-postgresql: unknown argument '" << prop.Name << "' having value: " << prop.Value ); + } + } +} + +void Connection::initialize( const Sequence< Any >& aArguments ) +{ + OUString url; + Sequence< PropertyValue > args; + + Reference< XTypeConverter > tc( Converter::create(m_ctx) ); + if( ! tc.is() ) + { + throw RuntimeException( + "pq_driver: Couldn't instantiate converter service" ); + } + if( aArguments.getLength() != 2 ) + { + throw IllegalArgumentException( + "pq_driver: expected 2 arguments, got " + OUString::number( aArguments.getLength( ) ), + Reference< XInterface > () , 0 ); + } + + if( ! (aArguments[0] >>= url) ) + { + throw IllegalArgumentException( + "pq_driver: expected string as first argument, got " + + aArguments[0].getValueType().getTypeName(), + *this, 0 ); + } + + tc->convertTo( aArguments[1], cppu::UnoType<decltype(args)>::get() ) >>= args; + + OString o; + int nColon = url.indexOf( ':' ); + if( nColon != -1 ) + { + nColon = url.indexOf( ':' , 1+ nColon ); + if( nColon != -1 ) + { + o = OUStringToOString( url.getStr()+nColon+1, ConnectionSettings::encoding ); + } + } + { + cstr_vector keywords; + cstr_vector values; + + if ( o.getLength() > 0 ) + { + char *err; + std::shared_ptr<PQconninfoOption> oOpts(PQconninfoParse(o.getStr(), &err), PQconninfoFree); + if (oOpts == nullptr) + { + OUString errorMessage; + if ( err != nullptr) + { + errorMessage = OUString( err, strlen(err), ConnectionSettings::encoding ); + free(err); + } + else + errorMessage = "#no error message#"; + // HY092 is "Invalid attribute/option identifier." + // Just the most likely error; the error might be HY024 "Invalid attribute value". + throw SQLException( + "Error in database URL '" + url + "':\n" + errorMessage, + *this, "HY092", 5, Any() ); + } + + for ( PQconninfoOption * opt = oOpts.get(); opt->keyword != nullptr; ++opt) + { + if ( opt->val != nullptr ) + { + keywords.push_back(strdup(opt->keyword)); + values.push_back(strdup(opt->val)); + } + } + } + properties2arrays( args , tc, ConnectionSettings::encoding, keywords, values ); + keywords.push_back(nullptr, SAL_NO_ACQUIRE); + values.push_back(nullptr, SAL_NO_ACQUIRE); + + m_settings.pConnection = PQconnectdbParams( keywords.c_array(), values.c_array(), 0 ); + } + if( ! m_settings.pConnection ) + throw RuntimeException("pq_driver: out of memory" ); + if( PQstatus( m_settings.pConnection ) == CONNECTION_BAD ) + { + const char * error = PQerrorMessage( m_settings.pConnection ); + OUString errorMessage( error, strlen( error) , RTL_TEXTENCODING_ASCII_US ); + PQfinish( m_settings.pConnection ); + m_settings.pConnection = nullptr; + throw SQLException( + "Couldn't establish database connection to '" + url + "'\n" + + errorMessage, + *this, errorMessage, CONNECTION_BAD, Any() ); + } + PQsetClientEncoding( m_settings.pConnection, "UNICODE" ); + char *p = PQuser( m_settings.pConnection ); + m_settings.user = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8); + p = PQdb( m_settings.pConnection ); + m_settings.catalog = OUString( p, strlen(p), RTL_TEXTENCODING_UTF8); + m_settings.tc = tc; + + SAL_INFO("connectivity.postgresql", "connection to '" << url << "' successfully opened"); +} + +void Connection::disposing() +{ + close(); +} + +void Connection::checkClosed() +{ + if( !m_settings.pConnection ) + throw SQLException( "pq_connection: Connection already closed", + *this, OUString(), 1, Any() ); +} + +Reference< XNameAccess > Connection::getTables() +{ + SAL_INFO("connectivity.postgresql", "Connection::getTables() got called"); + MutexGuard guard( m_xMutex->GetMutex() ); + if( !m_settings.tables.is() ) + m_settings.tables = Tables::create( m_xMutex, this, &m_settings , &m_settings.pTablesImpl); + else + // TODO: how to overcome the performance problem ? + Reference< css::util::XRefreshable > ( m_settings.tables, UNO_QUERY_THROW )->refresh(); + return m_settings.tables; +} + +Reference< XNameAccess > Connection::getViews() +{ + SAL_INFO("connectivity.postgresql", "Connection::getViews() got called"); + MutexGuard guard( m_xMutex->GetMutex() ); + if( !m_settings.views.is() ) + m_settings.views = Views::create( m_xMutex, this, &m_settings, &(m_settings.pViewsImpl) ); + else + // TODO: how to overcome the performance problem ? + Reference< css::util::XRefreshable > ( m_settings.views, UNO_QUERY_THROW )->refresh(); + return m_settings.views; +} + + +Reference< XNameAccess > Connection::getUsers() +{ + SAL_INFO("connectivity.postgresql", "Connection::getUsers() got called"); + + MutexGuard guard( m_xMutex->GetMutex() ); + if( !m_settings.users.is() ) + m_settings.users = Users::create( m_xMutex, this, &m_settings ); + return m_settings.users; +} + +/// @throws Exception +static Reference< XInterface > ConnectionCreateInstance( + const Reference< XComponentContext > & ctx ) +{ + ::rtl::Reference< comphelper::RefCountedMutex > ref = new comphelper::RefCountedMutex; + return * new Connection( ref, ctx ); +} + +} // end namespace + + +static const struct cppu::ImplementationEntry g_entries[] = +{ + { + pq_sdbc_driver::ConnectionCreateInstance, pq_sdbc_driver::ConnectionGetImplementationName, + pq_sdbc_driver::ConnectionGetSupportedServiceNames, cppu::createSingleComponentFactory, + nullptr , 0 + }, + { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } +}; + + +extern "C" +{ + +SAL_DLLPUBLIC_EXPORT void * postgresql_sdbc_impl_component_getFactory( + const char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + return cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey , g_entries ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_connection.hxx b/connectivity/source/drivers/postgresql/pq_connection.hxx new file mode 100644 index 000000000..f8d19c406 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_connection.hxx @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_CONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_CONNECTION_HXX + +#include <config_lgpl.h> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/sdbcx/XUsersSupplier.hpp> +#include <com/sun/star/sdbcx/XViewsSupplier.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> + +#include <com/sun/star/container/XNameAccess.hpp> + +#include <rtl/ref.hxx> +#include <rtl/byteseq.hxx> + +#include <comphelper/refcountedmutex.hxx> + +#include <cppuhelper/weakref.hxx> +#include <cppuhelper/compbase.hxx> +#include <functional> + +#include <libpq-fe.h> +#include <unordered_map> + +namespace pq_sdbc_driver +{ +struct ConnectionSettings; +class Tables; +class Views; +struct ConnectionSettings +{ + ConnectionSettings() : + pConnection(nullptr), + maxNameLen(0), + maxIndexKeys(0), + pTablesImpl(nullptr), + pViewsImpl(nullptr) + {} + static const rtl_TextEncoding encoding = RTL_TEXTENCODING_UTF8; + PGconn *pConnection; + sal_Int32 maxNameLen; + sal_Int32 maxIndexKeys; + css::uno::Reference< css::script::XTypeConverter > tc; + css::uno::Reference< css::container::XNameAccess > tables; + css::uno::Reference< css::container::XNameAccess > users; + css::uno::Reference< css::container::XNameAccess > views; + Tables *pTablesImpl; // needed to implement renaming of tables / views + Views *pViewsImpl; // needed to implement renaming of tables / views + OUString user; + OUString catalog; +}; + + +typedef cppu::WeakComponentImplHelper< + css::sdbc::XConnection, + css::sdbc::XWarningsSupplier, + css::lang::XInitialization, + css::sdbcx::XTablesSupplier, + css::sdbcx::XViewsSupplier, + css::sdbcx::XUsersSupplier > ConnectionBase; + +// some types +struct HashByteSequence +{ + sal_Int32 operator () ( const ::rtl::ByteSequence & seq ) const + { + return *reinterpret_cast<sal_Int32 const *>(seq.getConstArray()); + } +}; + +typedef std::unordered_map< + ::rtl::ByteSequence, + css::uno::WeakReference< css::sdbc::XCloseable >, + HashByteSequence > WeakHashMap; + + +typedef std::unordered_map +< + sal_Int32, + OUString +> Int2StringMap; + +class Connection : public ConnectionBase +{ + css::uno::Reference< css::uno::XComponentContext > m_ctx; + css::uno::Reference< css::container::XNameAccess > m_typeMap; + ConnectionSettings m_settings; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_meta; + WeakHashMap m_myStatements; + +private: + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkClosed(); + +public: + Connection( + const rtl::Reference< comphelper::RefCountedMutex > &refMutex, + const css::uno::Reference< css::uno::XComponentContext > & ctx ); + + virtual ~Connection( ) override; + +public: // XCloseable + virtual void SAL_CALL close() override; + +public: // XConnection + + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override ; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( + const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( + const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + +public: // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + +public: // XInitialization + virtual void SAL_CALL initialize( + const css::uno::Sequence< css::uno::Any >& aArguments ) override; + +public: // XTablesSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override; + +public: // XUsersSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getUsers( ) override; + +public: // XViewsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getViews( ) override; + +public: + virtual void SAL_CALL disposing() override; + +public: // helper function + void removeFromWeakMap( const ::rtl::ByteSequence & seq ); +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx b/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx new file mode 100644 index 000000000..4794d21e8 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_databasemetadata.cxx @@ -0,0 +1,2510 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + * Some portions were adapted from JDBC PostgreSQL driver: + * + * Copyright (c) 2004-2008, PostgreSQL Global Development Group + * + * Licence of original JDBC driver code: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the PostgreSQL Global Development Group nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************/ + +#include <algorithm> +#include <sal/log.hxx> +#include "pq_databasemetadata.hxx" +#include "pq_driver.hxx" +#include "pq_sequenceresultset.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +#include <rtl/ustrbuf.hxx> +#include <sal/macros.h> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/IndexType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/ColumnSearch.hpp> + +using ::osl::MutexGuard; + + +using namespace com::sun::star::sdbc; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; + +namespace pq_sdbc_driver +{ +// These are pre-processor versions of KeyRule.idl declarations +// These are inherited from JDBC, and thus won't change anytime soon. +// Having them as pre-processor definitions allows to include them +// into compile-time strings (through SAL_STRINGIFY), which can be passed to ASCII_STR. +// That is without resorting to horrendous hacks in template meta-programming. +#define KEYRULE_CASCADE 0 +#define KEYRULE_RESTRICT 1 +#define KEYRULE_SET_NULL 2 +#define KEYRULE_NO_ACTION 4 +#define KEYRULE_SET_DEFAULT 4 +// Ditto for Deferrability.idl +#define DEFERRABILITY_INITIALLY_DEFERRED 5 +#define DEFERRABILITY_INITIALLY_IMMEDIATE 6 +#define DEFERRABILITY_NONE 7 + +DatabaseMetaData::DatabaseMetaData( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : m_xMutex( refMutex ), + m_pSettings( pSettings ), + m_origin( origin ), + m_getIntSetting_stmt ( m_origin->prepareStatement("SELECT setting FROM pg_catalog.pg_settings WHERE name=?") ) +{ + init_getReferences_stmt(); + init_getPrivs_stmt(); +} + +sal_Bool DatabaseMetaData::allProceduresAreCallable( ) +{ + // TODO + return false; +} + +sal_Bool DatabaseMetaData::allTablesAreSelectable( ) +{ + return true; +} + +OUString DatabaseMetaData::getURL( ) +{ + // TODO + // LEM TODO: implement + return OUString(); +} + +OUString DatabaseMetaData::getUserName( ) +{ + return m_pSettings->user; +} + +sal_Bool DatabaseMetaData::isReadOnly( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::nullsAreSortedHigh( ) +{ + // Whether NULL values are considered, for sorting purposes, LARGER than any other value. + // Specification: http://download.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#nullsAreSortedHigh() + // PostgreSQL behaviour: http://www.postgresql.org/docs/9.1/static/queries-order.html + return true; +} + +sal_Bool DatabaseMetaData::nullsAreSortedLow( ) +{ + return ! nullsAreSortedHigh(); +} + +sal_Bool DatabaseMetaData::nullsAreSortedAtStart( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::nullsAreSortedAtEnd( ) +{ + return false; +} + +OUString DatabaseMetaData::getDatabaseProductName( ) +{ + return "PostgreSQL"; +} + +OUString DatabaseMetaData::getDatabaseProductVersion( ) +{ + return OUString::createFromAscii( PQparameterStatus( m_pSettings->pConnection, "server_version" ) ); +} +OUString DatabaseMetaData::getDriverName( ) +{ + return "postgresql-sdbc"; +} + +OUString DatabaseMetaData::getDriverVersion( ) +{ + return PQ_SDBC_DRIVER_VERSION; +} + +sal_Int32 DatabaseMetaData::getDriverMajorVersion( ) +{ + return PQ_SDBC_MAJOR; +} + +sal_Int32 DatabaseMetaData::getDriverMinorVersion( ) +{ + return PQ_SDBC_MINOR; +} + +sal_Bool DatabaseMetaData::usesLocalFiles( ) +{ + // LEM TODO: + // http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/XDatabaseMetaData_Interface + // says "Returns true when the catalog name of the + // database should not appear in the DatasourceBrowser + // of OpenOffice.org API, otherwise false is returned." + // So, hmmm, think about it. + return false; +} + +sal_Bool DatabaseMetaData::usesLocalFilePerTable( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsMixedCaseIdentifiers( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::storesUpperCaseIdentifiers( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::storesLowerCaseIdentifiers( ) +{ + return true; +} + + +sal_Bool DatabaseMetaData::storesMixedCaseIdentifiers( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::supportsMixedCaseQuotedIdentifiers( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::storesUpperCaseQuotedIdentifiers( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::storesLowerCaseQuotedIdentifiers( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::storesMixedCaseQuotedIdentifiers( ) +{ + return false; +} + + +OUString DatabaseMetaData::getIdentifierQuoteString( ) +{ + return "\""; +} + +OUString DatabaseMetaData::getSQLKeywords( ) +{ + // In Java 6, this is all keywords that are not SQL:2003 + // In Java 2 v1.4 and as per LibreOffice SDK doc, this is all keywords that are not SQL92 + // I understand this to mean "reserved keywords" only. + // See http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html + // LEM TODO: consider using pg_get_keywords(), filter on catcode + return + "ANALYSE," + "ANALYZE," + "ARRAY," //SQL:1999 + "ASYMMETRIC," //SQL:2003 + "BINARY," //SQL:1999 + "CONCURRENTLY," + "CURRENT_CATALOG," //SQL:2008 + "CURRENT_ROLE," //SQL:1999 + "CURRENT_SCHEMA," //SQL:2008 + "DO," + "FREEZE," + "ILIKE," + "ISNULL," + "LIMIT," //SQL:1999; non-reserved in SQL:2003 + "LOCALTIME," //SQL:1999 + "LOCALTIMESTAMP," //SQL:1999 + "NOTNULL," + "OFFSET," //SQL:2008 + "OVER," //SQL:2003 + "PLACING," //non-reserved in SQL:2003 + "RETURNING," //non-reserved in SQL:2008 + "SIMILAR," //SQL:2003 + "VARIADIC," + "VERBOSE," + "WINDOW" //SQL:2003 + ; +} +OUString DatabaseMetaData::getNumericFunctions( ) +{ + // See http://www.postgresql.org/docs/9.1/static/functions-math.html + // LEM TODO: Err... http://wiki.openoffice.org/wiki/Documentation/DevGuide/Database/Support_Scalar_Functions + // says this should be "Open Group CLI" names, not PostgreSQL names. + // Currently this is just a list of supported functions in PostgreSQL, with PostgreSQL names. + // And it is my job to map from Open Group CLI names/syntax to PostgreSQL names/syntax. Where? By parsing the SQL??? + // Should look at what the JDBC driver is doing. + return + "abs," + "cbrt," + "ceil," + "ceiling," + "degrees," + "div," + "exp," + "floor," + "ln," + "log," + "mod," + "pi," + "power," + "radians," + "random," + "round," + "setseed," + "sign," + "sqrt," + "trunc," + "width_bucket," + "acos," + "asin," + "atan," + "atan2," + "cos," + "cot," + "sin," + "tan" + ; +} + +OUString DatabaseMetaData::getStringFunctions( ) +{ + // See http://www.postgresql.org/docs/9.1/static/functions-string.html + return + "bit_length," + "char_length," + "character_length," + "lower," + "octet_length," + "overlay," + "position," + "substring," + "trim," + "upper," + "ascii," + "btrim," + "chr," + "concat," + "concat_ws," + "convert," + "convert_from," + "convert_to," + "decode," + "encode," + "format," + "initcap," + "left," + "length," + "lpad," + "ltrim," + "md5," + "pg_client_encoding," + "quote_ident," + "quote_literal," + "quote_nullable," + "regexp_matches," + "regexp_replace," + "regexp_split_to_array," + "regexp_split_to_table," + "repeat," + "replace," + "reverse," + "right," + "rpad," + "rtrim," + "split_part," + "strpos," + "substr," + "to_ascii," + "to_hex," + "translate" + ; +} + +OUString DatabaseMetaData::getSystemFunctions( ) +{ + // See http://www.postgresql.org/docs/9.1/static/functions-info.html + // and http://www.postgresql.org/docs/9.1/static/functions-admin.html + return + "current_catalog," + "current_database," + "current_query," + "current_schema," + "current_schemas," + "current_user," + "inet_client_addr," + "inet_client_port," + "inet_server_addr," + "inet_server_port," + "pg_backend_pid," + "pg_conf_load_time," + "pg_is_other_temp_schema," + "pg_listening_channels," + "pg_my_temp_schema," + "pg_postmaster_start_time," + "session_user," + "user," + "version," + "has_any_column_privilege," + "has_any_column_privilege," + "has_any_column_privilege," + "has_column_privilege," + "has_database_privilege," + "has_foreign_data_wrapper_privilege," + "has_function_privilege," + "has_language_privilege," + "has_schema_privilege," + "has_sequence_privilege," + "has_server_privilege," + "has_table_privilege," + "has_tablespace_privilege," + "pg_has_role," + "pg_collation_is_visible," + "pg_conversion_is_visible," + "pg_function_is_visible," + "pg_opclass_is_visible," + "pg_operator_is_visible," + "pg_table_is_visible," + "pg_ts_config_is_visible," + "pg_ts_dict_is_visible," + "pg_ts_parser_is_visible," + "pg_ts_template_is_visible," + "pg_type_is_visible," + "format_type," + "pg_describe_object," + "pg_get_constraintdef," + "pg_get_expr," + "pg_get_functiondef," + "pg_get_function_arguments," + "pg_get_function_identity_arguments," + "pg_get_function_result," + "pg_get_indexdef," + "pg_get_keywords," + "pg_get_ruledef," + "pg_get_serial_sequence," + "pg_get_triggerdef," + "pg_get_userbyid," + "pg_get_viewdef," + "pg_options_to_table," + "pg_tablespace_databases," + "pg_typeof," + "col_description," + "obj_description," + "shobj_description," + "txid_current," + "txid_current_snapshot," + "txid_snapshot_xip," + "txid_snapshot_xmax," + "txid_snapshot_xmin," + "txid_visible_in_snapshot," + "xmin," + "xmax," + "xip_list," + "current_setting," + "set_config," + "pg_cancel_backend," + "pg_reload_conf," + "pg_rotate_logfile," + "pg_terminate_backend," + "pg_create_restore_point," + "pg_current_xlog_insert_location," + "pg_current_xlog_location," + "pg_start_backup," + "pg_stop_backup," + "pg_switch_xlog," + "pg_xlogfile_name," + "pg_xlogfile_name_offset," + "pg_is_in_recovery," + "pg_last_xlog_receive_location," + "pg_last_xlog_replay_location," + "pg_last_xact_replay_timestamp," + "pg_is_xlog_replay_paused," + "pg_xlog_replay_pause," + "pg_xlog_replay_resume," + "pg_column_size," + "pg_database_size," + "pg_indexes_size," + "pg_relation_size," + "pg_size_pretty," + "pg_table_size," + "pg_tablespace_size," + "pg_tablespace_size," + "pg_total_relation_size," + "pg_relation_filenode," + "pg_relation_filepath," + "pg_ls_dir," + "pg_read_file," + "pg_read_binary_file," + "pg_stat_file," + "pg_advisory_lock," + "pg_advisory_lock_shared," + "pg_advisory_unlock," + "pg_advisory_unlock_all," + "pg_advisory_unlock_shared," + "pg_advisory_xact_lock," + "pg_advisory_xact_lock_shared," + "pg_try_advisory_lock," + "pg_try_advisory_lock_shared," + "pg_try_advisory_xact_lock," + "pg_try_advisory_xact_lock_shared," + "pg_sleep" + ; +} +OUString DatabaseMetaData::getTimeDateFunctions( ) +{ + // TODO + return + "age," + "age," + "clock_timestamp," + "current_date," + "current_time," + "current_timestamp," + "date_part," + "date_part," + "date_trunc," + "extract," + "extract," + "isfinite," + "isfinite," + "isfinite," + "justify_days," + "justify_hours," + "justify_interval," + "localtime," + "localtimestamp," + "now," + "statement_timestamp," + "timeofday," + "transaction_timestamp," + ; +} +OUString DatabaseMetaData::getSearchStringEscape( ) +{ + return "\\"; +} +OUString DatabaseMetaData::getExtraNameCharacters( ) +{ + return "$"; +} + +sal_Bool DatabaseMetaData::supportsAlterTableWithAddColumn( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsAlterTableWithDropColumn( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsColumnAliasing( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::nullPlusNonNullIsNull( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsTypeConversion( ) +{ + // LEM: this is specifically whether the "CONVERT" function is supported + // It seems that in PostgreSQL, that function is only for string encoding, so no. + return false; +} + +sal_Bool DatabaseMetaData::supportsConvert( sal_Int32, sal_Int32 ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsTableCorrelationNames( ) +{ + // LEM: A correlation name is "bar" in "SELECT foo FROM qux [AS] bar WHERE ..." + return true; +} + + +sal_Bool DatabaseMetaData::supportsDifferentTableCorrelationNames( ) +{ + return false; +} +sal_Bool DatabaseMetaData::supportsExpressionsInOrderBy( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsOrderByUnrelated( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsGroupBy( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsGroupByUnrelated( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsGroupByBeyondSelect( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsLikeEscapeClause( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsMultipleResultSets( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsMultipleTransactions( ) +{ + // Allows multiple transactions open at once (on different connections!) + return true; +} + +sal_Bool DatabaseMetaData::supportsNonNullableColumns( ) +{ + return true; +} + + +sal_Bool DatabaseMetaData::supportsMinimumSQLGrammar( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsCoreSQLGrammar( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + // fdo#45249 Base query design won't use any aggregate function + // (except COUNT(*) unless we say yes, so say yes. + // Actually, Base assumes *also* support for aggregate functions "collect, fusion, intersection" + // as soon as supportsCoreSQLGrammar() returns true. + // Those are *not* Core SQL, though. They are in optional feature S271 "Basic multiset support" + return true; +} + +sal_Bool DatabaseMetaData::supportsExtendedSQLGrammar( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsANSI92EntryLevelSQL( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsANSI92IntermediateSQL( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + return false; +} + +sal_Bool DatabaseMetaData::supportsANSI92FullSQL( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + return false; +} + +sal_Bool DatabaseMetaData::supportsIntegrityEnhancementFacility( ) +{ + // LEM: jdbc driver says yes, although comment says they are not sure what this means... + return true; +} + +sal_Bool DatabaseMetaData::supportsOuterJoins( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsFullOuterJoins( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsLimitedOuterJoins( ) +{ + return true; +} + + +OUString DatabaseMetaData::getSchemaTerm( ) +{ + return "SCHEMA"; +} + +OUString DatabaseMetaData::getProcedureTerm( ) +{ + return "function"; +} + +OUString DatabaseMetaData::getCatalogTerm( ) +{ + return "DATABASE"; +} + +sal_Bool DatabaseMetaData::isCatalogAtStart( ) +{ + return true; +} + +OUString DatabaseMetaData::getCatalogSeparator( ) +{ + return "."; +} + +sal_Bool DatabaseMetaData::supportsSchemasInDataManipulation( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSchemasInProcedureCalls( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSchemasInTableDefinitions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSchemasInIndexDefinitions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSchemasInPrivilegeDefinitions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsCatalogsInDataManipulation( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsCatalogsInProcedureCalls( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsCatalogsInTableDefinitions( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::supportsCatalogsInIndexDefinitions( ) +{ + return false; +} + + +sal_Bool DatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( ) +{ + return false; +} + + +// LEM TODO: positioned (through cursor) updates and deletes seem +// to be supported; see {UPDATE,DELETE} /table/ (...) WHERE CURRENT OF /cursor_name/" syntax +// and http://www.postgresql.org/docs/9.1/static/view-pg-cursors.html +// http://www.postgresql.org/docs/9.1/static/libpq-example.html actually uses a cursor :) +sal_Bool DatabaseMetaData::supportsPositionedDelete( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + return false; +} + +sal_Bool DatabaseMetaData::supportsPositionedUpdate( ) +{ + // LEM: jdbc driver says not, although the comments in it seem old + return false; +} + + +sal_Bool DatabaseMetaData::supportsSelectForUpdate( ) +{ + return true; +} + + +sal_Bool DatabaseMetaData::supportsStoredProcedures( ) +{ + return true; +} + + +sal_Bool DatabaseMetaData::supportsSubqueriesInComparisons( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSubqueriesInExists( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSubqueriesInIns( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsSubqueriesInQuantifieds( ) +{ + // LEM: jdbc driver says yes, although comment says they don't know what this means... + return true; +} + +sal_Bool DatabaseMetaData::supportsCorrelatedSubqueries( ) +{ + return true; +} +sal_Bool DatabaseMetaData::supportsUnion( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsUnionAll( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossCommit( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsOpenCursorsAcrossRollback( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossCommit( ) +{ + return true; +} +sal_Bool DatabaseMetaData::supportsOpenStatementsAcrossRollback( ) +{ + return true; +} + +sal_Int32 DatabaseMetaData::getMaxBinaryLiteralLength( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxCharLiteralLength( ) +{ + return 0; +} + +// Copied / adapted / simplified from JDBC driver +sal_Int32 DatabaseMetaData::getIntSetting(const OUString& settingName) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + Reference< XParameters > params(m_getIntSetting_stmt, UNO_QUERY_THROW ); + params->setString(1, settingName ); + Reference< XResultSet > rs = m_getIntSetting_stmt->executeQuery(); + Reference< XRow > xRow( rs , UNO_QUERY_THROW ); + OSL_VERIFY(rs->next()); + OSL_ENSURE(rs->isFirst(), "postgresql-sdbc DatabaseMetaData getIntSetting not on first row"); + OSL_ENSURE(rs->isLast(), "postgresql-sdbc DatabaseMetaData getIntSetting not on last row"); + return xRow->getInt(1); +} + +sal_Int32 DatabaseMetaData::getMaxNameLength() +{ + if ( m_pSettings->maxNameLen == 0) + m_pSettings->maxNameLen = getIntSetting( "max_identifier_length" ); + OSL_ENSURE(m_pSettings->maxNameLen, "postgresql-sdbc: maxNameLen is zero"); + return m_pSettings->maxNameLen; +} + +sal_Int32 DatabaseMetaData::getMaxIndexKeys() +{ + if ( m_pSettings->maxIndexKeys == 0) + m_pSettings->maxIndexKeys = getIntSetting("max_index_keys"); + OSL_ENSURE(m_pSettings->maxIndexKeys, "postgresql-sdbc: maxIndexKeys is zero"); + return m_pSettings->maxIndexKeys; +} + +sal_Int32 DatabaseMetaData::getMaxColumnNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInGroupBy( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInIndex( ) +{ + return getMaxIndexKeys(); +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInOrderBy( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInSelect( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxColumnsInTable( ) +{ + return 1600; +} + +sal_Int32 DatabaseMetaData::getMaxConnections( ) +{ + // LEM: The JDBC driver returns an arbitrary 8192; truth is as much as OS / hardware supports + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxCursorNameLength( ) //TODO, don't know +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxIndexLength( ) //TODO, don't know +{ + // LEM: that's the index itself, not its name + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxSchemaNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxProcedureNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxCatalogNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxRowSize( ) +{ + // jdbc driver says 1GB, but http://www.postgresql.org/about/ says 1.6TB + // and that 1GB is the maximum _field_ size + // The row limit does not fit into a sal_Int32 + return 0; +} + +sal_Bool DatabaseMetaData::doesMaxRowSizeIncludeBlobs( ) +{ + // LEM: Err... PostgreSQL basically does not do BLOBs well + // In any case, BLOBs do not change the maximal row length AFAIK + return true; +} + +sal_Int32 DatabaseMetaData::getMaxStatementLength( ) +{ + // LEM: actually, that would be 2^sizeof(size_t)-1 + // on the server? on the client (because of libpq)? minimum of the two? not sure + // Anyway, big, so say unlimited. + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxStatements( ) //TODO, don't know +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxTableNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getMaxTablesInSelect( ) +{ + return 0; +} + +sal_Int32 DatabaseMetaData::getMaxUserNameLength( ) +{ + return getMaxNameLength(); +} + +sal_Int32 DatabaseMetaData::getDefaultTransactionIsolation( ) +{ + return css::sdbc::TransactionIsolation::READ_COMMITTED; +} + +sal_Bool DatabaseMetaData::supportsTransactions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 level ) +{ + if ( level == css::sdbc::TransactionIsolation::READ_COMMITTED + || level == css::sdbc::TransactionIsolation::SERIALIZABLE + || level == css::sdbc::TransactionIsolation::READ_UNCOMMITTED + || level == css::sdbc::TransactionIsolation::REPEATABLE_READ) + return true; + else + return false; +} + +sal_Bool DatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( ) +{ + return true; +} + +sal_Bool DatabaseMetaData::supportsDataManipulationTransactionsOnly( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::dataDefinitionCausesTransactionCommit( ) +{ + return false; +} + +sal_Bool DatabaseMetaData::dataDefinitionIgnoredInTransactions( ) +{ + return false; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getProcedures( + const css::uno::Any&, + const OUString&, + const OUString& ) +{ +// 1. PROCEDURE_CAT string => procedure catalog (may be NULL ) +// 2. PROCEDURE_SCHEM string => procedure schema (may be NULL ) +// 3. PROCEDURE_NAME string => procedure name +// 4. reserved for future use +// 5. reserved for future use +// 6. reserved for future use +// 7. REMARKS string => explanatory comment on the procedure +// 8. PROCEDURE_TYPE short => kind of procedure: +// * UNKNOWN - May return a result +// * NO - Does not return a result +// * RETURN - Returns a result + +// LEM TODO: implement +// LEM TODO: at least fake the columns, even if no row. + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > > (), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getProcedureColumns( + const css::uno::Any&, + const OUString&, + const OUString&, + const OUString& ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); +// LEM TODO: implement +// LEM TODO: at least fake the columns, even if no row. + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getTables( + const css::uno::Any&, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence< OUString >& ) +{ + Statics &statics = getStatics(); + + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTables() got called with " << schemaPattern << "." << tableNamePattern); + + // ignore catalog, as a single pq connection does not support multiple catalogs + + // LEM TODO: this does not give the right column names, not the right number of columns, etc. + // Take "inspiration" from JDBC driver + // Ah, this is used to create a XResultSet manually... Try to do it directly in SQL + Reference< XPreparedStatement > statement = m_origin->prepareStatement( + "SELECT " + "DISTINCT ON (pg_namespace.nspname, relname ) " // avoid duplicates (pg_settings !) + "pg_namespace.nspname, relname, relkind, pg_description.description " + "FROM pg_namespace, pg_class LEFT JOIN pg_description ON pg_class.oid = pg_description.objoid " + "WHERE relnamespace = pg_namespace.oid " + "AND ( relkind = 'r' OR relkind = 'v') " + "AND pg_namespace.nspname LIKE ? " + "AND relname LIKE ? " +// "ORDER BY pg_namespace.nspname || relname" + ); + + Reference< XParameters > parameters( statement, UNO_QUERY_THROW ); + parameters->setString( 1 , schemaPattern ); + parameters->setString( 2 , tableNamePattern ); + + Reference< XResultSet > rs = statement->executeQuery(); + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + std::vector< std::vector<Any> > vec; + + while( rs->next() ) + { + std::vector< Any > row( 5 ); + + row[0] <<= m_pSettings->catalog; + row[1] <<= xRow->getString( 1 ); + row[2] <<= xRow->getString( 2 ); + OUString type = xRow->getString(3); + if( type == "r" ) + { + if( xRow->getString(1) == "pg_catalog" ) + { + row[3] <<= statics.SYSTEM_TABLE; + } + else + { + row[3] <<= statics.TABLE; + } + } + else if( type == "v" ) + { + row[3] <<= statics.VIEW; + } + else + { + row[3] <<= statics.UNKNOWN; + } + row[4] <<= xRow->getString(4); + + // no description in postgresql AFAIK + vec.push_back( row ); + } + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + + return new SequenceResultSet( + m_xMutex, *this, statics.tablesRowNames, vec, m_pSettings->tc ); +} + +namespace +{ + // sort no schema first, then "public", then normal schemas, then internal schemas + int compare_schema(const OUString &nsA, const OUString &nsB) + { + if (nsA.isEmpty()) + { + return nsB.isEmpty() ? 0 : -1; + } + else if (nsB.isEmpty()) + { + assert(!nsA.isEmpty()); + return 1; + } + else if(nsA == "public") + { + return (nsB == "public") ? 0 : -1; + } + else if(nsB == "public") + { + assert(nsA != "public"); + return 1; + } + else if(nsA.startsWith("pg_")) + { + if(nsB.startsWith("pg_")) + return nsA.compareTo(nsB); + else + return 1; + } + else if(nsB.startsWith("pg_")) + { + return -1; + } + else + { + return nsA.compareTo(nsB); + } + } + + struct SortInternalSchemasLastAndPublicFirst + { + bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b ) + { + OUString valueA; + OUString valueB; + a[0] >>= valueA; + b[0] >>= valueB; + return compare_schema(valueA, valueB); + } + }; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getSchemas( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getSchemas() got called"); + + // <b>TABLE_SCHEM</b> string =&gt; schema name + Reference< XStatement > statement = m_origin->createStatement(); + Reference< XResultSet > rs = statement->executeQuery( + "SELECT nspname from pg_namespace" ); + // LEM TODO: look at JDBC driver and consider doing the same + // in particular, excluding temporary schemas, but maybe better through pg_is_other_temp_schema(oid) OR == pg_my_temp_schema() + + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + std::vector< std::vector<Any> > vec; + while( rs->next() ) + { + std::vector<Any> row(1); + row[0] <<= xRow->getString(1); + vec.push_back( row ); + } + + // sort public first, sort internal schemas last, sort rest in alphabetic order + std::sort( vec.begin(), vec.end(), SortInternalSchemasLastAndPublicFirst() ); + + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + return new SequenceResultSet( + m_xMutex, *this, getStatics().schemaNames, vec, m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getCatalogs( ) +{ + // LEM TODO: return the current catalog like JDBC driver? + // at least fake the columns, even if no content + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getTableTypes( ) +{ + // LEM TODO: this can be made dynamic, see JDBC driver + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, getStatics().tableTypeNames, getStatics().tableTypeData, + m_pSettings->tc ); +} + + +/** returns the constant from sdbc.DataType + */ +sal_Int32 typeNameToDataType( const OUString &typeName, const OUString &typtype ) +{ +// sal_Int32 ret = css::sdbc::DataType::DISTINCT; + // map all unknown types to memo (longvarchar). This allows to show them in + // string representation. Additionally, the edit-table-type-selection-box + // is not so unusable anymore. + sal_Int32 ret = css::sdbc::DataType::LONGVARCHAR; + if( typtype == "b" ) + { + // as long as the OOo framework does not support arrays, + // the user is better of with interpreting arrays as strings ! +// if( typeName.getLength() && '_' == typeName[0] ) +// { +// it's just a naming convention, but as long as we don't have anything better, +// we take it as granted +// ret = css::sdbc::DataType::ARRAY; +// } + // base type + Statics &statics = getStatics(); + BaseTypeMap::const_iterator ii = statics.baseTypeMap.find( typeName ); + if( ii != statics.baseTypeMap.end() ) + { + ret = ii->second; + } + } + else if( typtype == "c" ) + { + ret = css::sdbc::DataType::STRUCT; + } + else if( typtype == "d" ) + { + ret = css::sdbc::DataType::LONGVARCHAR; + } + return ret; +} + +namespace { + bool isSystemColumn( sal_Int16 attnum ) + { + return attnum <= 0; + } + + // is not exported by the postgres header + const int PQ_VARHDRSZ = sizeof( sal_Int32 ); + + // Oh, quelle horreur + // LEM TODO: Need to severely rewrite that! + // should probably just "do the same" as ODBC or JDBC drivers... + void extractPrecisionAndScale( + sal_Int32 dataType, sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale ) + { + if( atttypmod < PQ_VARHDRSZ ) + { + *precision = 0; + *scale = 0; + } + else + { + switch( dataType ) + { + case css::sdbc::DataType::NUMERIC: + case css::sdbc::DataType::DECIMAL: + { + *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff; + *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff; + break; + } + default: + *precision = atttypmod - PQ_VARHDRSZ; + *scale = 0; + } + } + } + + struct DatabaseTypeDescription + { + DatabaseTypeDescription() + {} + DatabaseTypeDescription( const OUString &name, const OUString & type ) : + typeName( name ), + typeType( type ) + {} + DatabaseTypeDescription( const DatabaseTypeDescription &source ) : + typeName( source.typeName ), + typeType( source.typeType ) + {} + DatabaseTypeDescription & operator = ( const DatabaseTypeDescription & source ) + { + typeName = source.typeName; + typeType = source.typeType; + return *this; + } + OUString typeName; + OUString typeType; + }; +} + +typedef std::unordered_map +< + sal_Int32, + DatabaseTypeDescription +> Oid2DatabaseTypeDescriptionMap; + +static void columnMetaData2DatabaseTypeDescription( + Oid2DatabaseTypeDescriptionMap &oidMap, + const Reference< XResultSet > &rs, + const Reference< XStatement > &stmt ) +{ + Reference< XRow > row( rs, UNO_QUERY_THROW ); + int domains = 0; + OUStringBuffer queryBuf(128); + queryBuf.append( "SELECT oid,typtype,typname FROM pg_TYPE WHERE " ); + while( rs->next() ) + { + if( row->getString( 9 ) == "d" && oidMap.find( row->getInt( 12 ) ) == oidMap.end() ) + { + oidMap[row->getInt(12)] = DatabaseTypeDescription(); + if( domains ) + queryBuf.append( " OR " ); + queryBuf.append( "oid = " ); + queryBuf.append( row->getInt(12 ) ); + domains ++; + } + } + rs->beforeFirst(); + + if( domains ) + { + Reference< XResultSet > rsDomain = stmt->executeQuery( queryBuf.makeStringAndClear() ); + row.set( rsDomain, UNO_QUERY_THROW ); + while( rsDomain->next() ) + { + oidMap[row->getInt(1)] = DatabaseTypeDescription(row->getString(3), row->getString(2) ); + } + disposeNoThrow( stmt ); + } + +} + + +css::uno::Reference< XResultSet > DatabaseMetaData::getColumns( + const css::uno::Any&, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + // LEM TODO: review in comparison with JDBC driver + Statics &statics = getStatics(); + + // continue ! + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumns() got called with " + << schemaPattern << "." << tableNamePattern << "." << columnNamePattern); + + // ignore catalog, as a single pq connection + // does not support multiple catalogs anyway + // We don't use information_schema.columns because it contains + // only the columns the current user has any privilege over. + + // 1. TABLE_CAT string => table catalog (may be NULL) + // => not supported + // 2. TABLE_SCHEM string => table schema (may be NULL) + // => pg_namespace.nspname + // 3. TABLE_NAME string => table name + // => pg_class.relname + // 4. COLUMN_NAME string => column name + // => pg_attribute.attname + // 5. DATA_TYPE short => SQL type from java.sql.Types + // => pg_type.typname => sdbc.DataType + // 6. TYPE_NAME string => Data source dependent type name, for a UDT the + // type name is fully qualified + // => pg_type.typname + // 7. COLUMN_SIZE long => column size. For char or date types this is + // the maximum number of characters, for numeric + // or decimal types this is precision. + // => pg_attribute.atttypmod + // 8. BUFFER_LENGTH is not used. + // => not used + // 9. DECIMAL_DIGITS long => the number of fractional digits + // => don't know ! TODO ! + // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2) + // => TODO ?? + // 11. NULLABLE long => is NULL allowed? + // NO_NULLS - might not allow NULL values + // NULABLE - definitely allows NULL values + // NULLABLE_UNKNOWN - nullability unknown + // => pg_attribute.attnotnull + // 12. REMARKS string => comment describing column (may be NULL ) + // => pg_description.description + // 13. COLUMN_DEF string => default value (may be NULL) + // => pg_type.typdefault + // 14. SQL_DATA_TYPE long => unused + // => empty + // 15. SQL_DATETIME_SUB long => unused + // => empty + // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of + // bytes in the column + // => pg_type.typlen + // 17. ORDINAL_POSITION int => index of column in table (starting at 1) + // pg_attribute.attnum + // 18. IS_NULLABLE string => "NO" means column definitely does not allow + // NULL values; "YES" means the column might + // allow NULL values. An empty string means + // nobody knows. + // => pg_attribute.attnotnull + OUString strDefaultValue = getColExprForDefaultSettingVal(m_pSettings); + Reference< XPreparedStatement > statement = m_origin->prepareStatement( + "SELECT pg_namespace.nspname, " // 1 + "pg_class.relname, " // 2 + "pg_attribute.attname, " // 3 + "pg_type.typname, " // 4 + "pg_attribute.atttypmod, " // 5 + "pg_attribute.attnotnull, " // 6 + "pg_type.typdefault, " // 7 + "pg_type.typtype, " // 8 + + strDefaultValue + // 9 + ",pg_description.description, " // 10 + "pg_type.typbasetype, " // 11 + "pg_attribute.attnum " // 12 + "FROM pg_class, " + "pg_attribute LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND pg_attribute.attnum = pg_attrdef.adnum " + "LEFT JOIN pg_description ON pg_attribute.attrelid = pg_description.objoid AND pg_attribute.attnum=pg_description.objsubid," + " pg_type, pg_namespace " + "WHERE pg_attribute.attrelid = pg_class.oid " + "AND pg_attribute.atttypid = pg_type.oid " + "AND pg_class.relnamespace = pg_namespace.oid " + "AND NOT pg_attribute.attisdropped " + "AND pg_namespace.nspname LIKE ? " + "AND pg_class.relname LIKE ? " + "AND pg_attribute.attname LIKE ? " + "ORDER BY pg_namespace.nspname, pg_class.relname, pg_attribute.attnum" + ); + + Reference< XParameters > parameters( statement, UNO_QUERY_THROW ); + parameters->setString( 1 , schemaPattern ); + parameters->setString( 2 , tableNamePattern ); + parameters->setString( 3 , columnNamePattern ); + + Reference< XResultSet > rs = statement->executeQuery(); + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + std::vector< std::vector<Any> > vec; + + Oid2DatabaseTypeDescriptionMap domainMap; + Reference< XStatement > domainTypeStmt = m_origin->createStatement(); + columnMetaData2DatabaseTypeDescription( domainMap, rs, domainTypeStmt ); + + sal_uInt32 colNum(0); + OUString sSchema( "#invalid#" ); + OUString sTable( "#invalid#" ); + + while( rs->next() ) + { + if( ! isSystemColumn( xRow->getShort( 12 ) ) ) + { + OUString sNewSchema( xRow->getString(1) ); + OUString sNewTable( xRow->getString(2) ); + if ( sNewSchema != sSchema || sNewTable != sTable ) + { + colNum = 1; + sSchema = sNewSchema; + sTable = sNewTable; + } + else + ++colNum; + sal_Int32 precision, scale, type; + std::vector< Any > row( 18 ); + row[0] <<= m_pSettings->catalog; + row[1] <<= sNewSchema; + row[2] <<= sNewTable; + row[3] <<= xRow->getString(3); + if( xRow->getString(8) == "d" ) + { + DatabaseTypeDescription desc( domainMap[xRow->getInt(11)] ); + type = typeNameToDataType( desc.typeName, desc.typeType ); + } + else + { + type = typeNameToDataType( xRow->getString(4), xRow->getString(8) ); + } + extractPrecisionAndScale( type, xRow->getInt(5) , &precision, &scale ); + row[4] <<= type; + row[5] <<= xRow->getString(4); + row[6] <<= precision; + // row[7] BUFFER_LENGTH not used + row[8] <<= scale; + // row[9] RADIX TODO + if( xRow->getBoolean( 6 ) && ! isSystemColumn(xRow->getInt( 12 )) ) + { + row[10] <<= OUString::number(css::sdbc::ColumnValue::NO_NULLS); + row[17] <<= statics.NO; + } + else + { + row[10] <<= OUString::number(css::sdbc::ColumnValue::NULLABLE); + row[17] <<= statics.YES; + } + + row[11] <<= xRow->getString( 10 ); // comment + row[12] <<= xRow->getString( 9 ); // COLUMN_DEF = pg_type.typdefault + // row[13] SQL_DATA_TYPE not used + // row[14] SQL_DATETIME_SUB not used + row[15] <<= precision; + row[16] <<= colNum ; + + vec.push_back( row ); + } + } + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + + return new SequenceResultSet( + m_xMutex, *this, statics.columnRowNames, vec, m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getColumnPrivileges( + const css::uno::Any&, + const OUString& schema, + const OUString& table, + const OUString& columnNamePattern ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getColumnPrivileges() got called with " + << schema << "." << table << "." << columnNamePattern); + + Reference< XParameters > parameters( m_getColumnPrivs_stmt, UNO_QUERY_THROW ); + parameters->setString( 1 , schema ); + parameters->setString( 2 , table ); + parameters->setString( 3 , columnNamePattern ); + + Reference< XResultSet > rs = m_getColumnPrivs_stmt->executeQuery(); + + return rs; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getTablePrivileges( + const css::uno::Any&, + const OUString& schemaPattern, + const OUString& tableNamePattern ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTablePrivileges() got called with " + << schemaPattern << "." << tableNamePattern); + + Reference< XParameters > parameters( m_getTablePrivs_stmt, UNO_QUERY_THROW ); + parameters->setString( 1 , schemaPattern ); + parameters->setString( 2 , tableNamePattern ); + + Reference< XResultSet > rs = m_getTablePrivs_stmt->executeQuery(); + + return rs; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getBestRowIdentifier( + const css::uno::Any&, + const OUString&, + const OUString&, + sal_Int32, + sal_Bool ) +{ + //LEM TODO: implement! See JDBC driver + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getVersionColumns( + const css::uno::Any&, + const OUString&, + const OUString& ) +{ + //LEM TODO: implement! See JDBC driver + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getPrimaryKeys( + const css::uno::Any&, + const OUString& schema, + const OUString& table ) +{ + //LEM TODO: review + MutexGuard guard( m_xMutex->GetMutex() ); + +// 1. TABLE_CAT string => table catalog (may be NULL ) +// 2. TABLE_SCHEM string => table schema (may be NULL ) +// 3. TABLE_NAME string => table name +// 4. COLUMN_NAME string => column name +// 5. KEY_SEQ short => sequence number within primary key +// 6. PK_NAME string => primary key name (may be NULL ) + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getPrimaryKeys() got called with " + << schema << "." << table); + + Reference< XPreparedStatement > statement = m_origin->prepareStatement( + "SELECT nmsp.nspname, " + "cl.relname, " + "con.conkey, " + "con.conname, " + "con.conrelid " + "FROM pg_constraint as con,pg_class as cl, pg_namespace as nmsp " + "WHERE con.connamespace = nmsp.oid AND con.conrelid = cl.oid AND con.contype = 'p' " + "AND nmsp.nspname LIKE ? AND cl.relname LIKE ?" ); + + Reference< XParameters > parameters( statement, UNO_QUERY_THROW ); + parameters->setString( 1 , schema ); + parameters->setString( 2 , table ); + + Reference< XResultSet > rs = statement->executeQuery(); + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + std::vector< std::vector<Any> > vec; + + while( rs->next() ) + { + std::vector< Any > row( 6 ); + row[0] <<= m_pSettings->catalog; + row[1] <<= xRow->getString(1); + row[2] <<= xRow->getString(2); + OUString array = xRow->getString(3); + row[4] <<= xRow->getString(5); // the relid + row[5] <<= xRow->getString(4); + + int i = 0; + // now retrieve the columns information + // unfortunately, postgresql does not allow array of variable size in + // WHERE clauses (in the default installation), so we have to choose + // this expensive and somewhat ugly way + // annotation: postgresql shouldn't have chosen an array here, instead they + // should have multiple rows per table + // LEM: to transform an array into several rows, see unnest; + // it is as simple as "SELECT foo, bar, unnest(qux) FROM ..." + // where qux is the column that contains an array. + while( array[i] && '}' != array[i] ) + { + i++; + int start = i; + while( array[i] && array[i] != '}' && array[i] != ',' ) i++; + row[3] <<= array.copy(start, i - start ); + vec.push_back( row ); + } + } + + { + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + } + + + OUString lastTableOid; + sal_Int32 index = 0; + std::vector< std::vector< Any > > ret( vec.size() ); + int elements = 0; + for (auto const& elem : vec) + { + + std::vector< Any > row = elem; + OUString tableOid; + OUString attnum; + + row[4] >>= tableOid; + row[3] >>= attnum; + statement = m_origin->prepareStatement( + "SELECT att.attname FROM " + "pg_attribute AS att, pg_class AS cl WHERE " + "att.attrelid = ? AND att.attnum = ?" ); + + parameters.set( statement, UNO_QUERY_THROW ); + parameters->setString( 1 , tableOid ); + parameters->setString( 2 , attnum ); + + rs = statement->executeQuery(); + xRow.set( rs, UNO_QUERY_THROW ); + if( rs->next() ) + { + // column name + row[3] <<= xRow->getString( 1 ); + if( tableOid != lastTableOid ) + index = 1; + lastTableOid = tableOid; + row[4] <<= OUString::number( index ); + index ++; + } + { + Reference< XCloseable > closeable( statement, UNO_QUERY ); + if( closeable.is() ) + closeable->close(); + } + ret[elements] = row; + elements ++; + } + return new SequenceResultSet( + m_xMutex, *this, getStatics().primaryKeyNames, ret, m_pSettings->tc ); +} + +// Copied / adapted / simplified from JDBC driver +#define SQL_CASE_KEYRULE " WHEN 'c' THEN " SAL_STRINGIFY(KEYRULE_CASCADE) \ + " WHEN 'n' THEN " SAL_STRINGIFY(KEYRULE_SET_NULL) \ + " WHEN 'd' THEN " SAL_STRINGIFY(KEYRULE_SET_DEFAULT) \ + " WHEN 'r' THEN " SAL_STRINGIFY(KEYRULE_RESTRICT) \ + " WHEN 'a' THEN " SAL_STRINGIFY(KEYRULE_NO_ACTION) \ + " ELSE NULL " + +#define SQL_GET_REFERENCES \ + "WITH con AS (SELECT oid, conname, contype, condeferrable, condeferred, conrelid, confrelid, confupdtype, confdeltype, generate_subscripts(conkey,1) AS conkeyseq, unnest(conkey) AS conkey , unnest(confkey) AS confkey FROM pg_catalog.pg_constraint) " \ + "SELECT NULL::text AS PKTABLE_CAT, pkn.nspname AS PKTABLE_SCHEM, pkc.relname AS PKTABLE_NAME, pka.attname AS PKCOLUMN_NAME, " \ + " NULL::text AS FKTABLE_CAT, fkn.nspname AS FKTABLE_SCHEM, fkc.relname AS FKTABLE_NAME, fka.attname AS FKCOLUMN_NAME, " \ + " con.conkeyseq AS KEY_SEQ, " \ + " CASE con.confupdtype " \ + SQL_CASE_KEYRULE \ + " END AS UPDATE_RULE, " \ + " CASE con.confdeltype " \ + SQL_CASE_KEYRULE \ + " END AS DELETE_RULE, " \ + " con.conname AS FK_NAME, pkic.relname AS PK_NAME, " \ + " CASE " \ + " WHEN con.condeferrable AND con.condeferred THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_DEFERRED) \ + " WHEN con.condeferrable THEN " SAL_STRINGIFY(DEFERRABILITY_INITIALLY_IMMEDIATE) \ + " ELSE " SAL_STRINGIFY(DEFERRABILITY_NONE) \ + " END AS DEFERRABILITY " \ + "FROM " \ + " pg_catalog.pg_namespace pkn, pg_catalog.pg_class pkc, pg_catalog.pg_attribute pka, " \ + " pg_catalog.pg_namespace fkn, pg_catalog.pg_class fkc, pg_catalog.pg_attribute fka, " \ + " con, pg_catalog.pg_depend dep, pg_catalog.pg_class pkic " \ + "WHERE pkn.oid = pkc.relnamespace AND pkc.oid = pka.attrelid AND pka.attnum = con.confkey AND con.confrelid = pkc.oid " \ + " AND fkn.oid = fkc.relnamespace AND fkc.oid = fka.attrelid AND fka.attnum = con.conkey AND con.conrelid = fkc.oid " \ + " AND con.contype = 'f' AND con.oid = dep.objid AND pkic.oid = dep.refobjid AND pkic.relkind = 'i' AND dep.classid = 'pg_constraint'::regclass::oid AND dep.refclassid = 'pg_class'::regclass::oid " + +#define SQL_GET_REFERENCES_PSCHEMA " AND pkn.nspname = ? " +#define SQL_GET_REFERENCES_PTABLE " AND pkc.relname = ? " +#define SQL_GET_REFERENCES_FSCHEMA " AND fkn.nspname = ? " +#define SQL_GET_REFERENCES_FTABLE " AND fkc.relname = ? " +#define SQL_GET_REFERENCES_ORDER_SOME_PTABLE "ORDER BY fkn.nspname, fkc.relname, conkeyseq" +#define SQL_GET_REFERENCES_ORDER_NO_PTABLE "ORDER BY pkn.nspname, pkc.relname, conkeyseq" + +#define SQL_GET_REFERENCES_NONE_NONE_NONE_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_SOME_NONE_NONE_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_NONE_SOME_NONE_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_SOME_SOME_NONE_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_NONE_NONE_SOME_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_NONE_NONE_NONE_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_NONE_NONE_SOME_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_SOME_NONE_SOME_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_SOME_NONE_NONE_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_SOME_NONE_SOME_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_NO_PTABLE + +#define SQL_GET_REFERENCES_NONE_SOME_SOME_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_NONE_SOME_NONE_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_NONE_SOME_SOME_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_SOME_SOME_SOME_NONE \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_SOME_SOME_NONE_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +#define SQL_GET_REFERENCES_SOME_SOME_SOME_SOME \ + SQL_GET_REFERENCES \ + SQL_GET_REFERENCES_PSCHEMA \ + SQL_GET_REFERENCES_PTABLE \ + SQL_GET_REFERENCES_FSCHEMA \ + SQL_GET_REFERENCES_FTABLE \ + SQL_GET_REFERENCES_ORDER_SOME_PTABLE + +void DatabaseMetaData::init_getReferences_stmt () +{ + m_getReferences_stmt[0] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_NONE); + m_getReferences_stmt[1] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_NONE); + m_getReferences_stmt[2] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_NONE); + m_getReferences_stmt[3] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_NONE); + m_getReferences_stmt[4] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_NONE); + m_getReferences_stmt[5] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_NONE); + m_getReferences_stmt[6] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_NONE); + m_getReferences_stmt[7] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_NONE); + m_getReferences_stmt[8] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_NONE_SOME); + m_getReferences_stmt[9] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_NONE_SOME); + m_getReferences_stmt[10] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_NONE_SOME); + m_getReferences_stmt[11] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_NONE_SOME); + m_getReferences_stmt[12] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_NONE_SOME_SOME); + m_getReferences_stmt[13] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_NONE_SOME_SOME); + m_getReferences_stmt[14] = m_origin->prepareStatement(SQL_GET_REFERENCES_NONE_SOME_SOME_SOME); + m_getReferences_stmt[15] = m_origin->prepareStatement(SQL_GET_REFERENCES_SOME_SOME_SOME_SOME); +} + +void DatabaseMetaData::init_getPrivs_stmt () +{ + OUStringBuffer sSQL(300); + sSQL.append( + " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.privilege, dp.is_grantable " + " FROM (" + " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name," + " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable" + " FROM information_schema.table_privileges"); + if ( PQserverVersion( m_pSettings->pConnection ) < 90200 ) + // information_schema.table_privileges does not fill in default ACLs when no ACL + // assume default ACL is "owner has all privileges" and add it + sSQL.append( + " UNION " + " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME," + " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable" + " FROM pg_catalog.pg_class c," + " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) p (privilege)," + " pg_catalog.pg_roles ro," + " ( SELECT oid, rolname FROM pg_catalog.pg_roles" + " UNION ALL" + " VALUES (0::oid, 'PUBLIC')" + " ) AS rg (oid, rolname)," + " pg_catalog.pg_namespace pn" + " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')" + " AND c.relowner=ro.oid AND c.relnamespace = pn.oid"); + sSQL.append( + " ) dp," + " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr" + " WHERE table_schem LIKE ? AND table_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))" + " ORDER BY table_schem, table_name, privilege" ); + + m_getTablePrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() ); + + sSQL.append( + " SELECT dp.TABLE_CAT, dp.TABLE_SCHEM, dp.TABLE_NAME, dp.COLUMN_NAME, dp.GRANTOR, pr.rolname AS GRANTEE, dp.PRIVILEGE, dp.IS_GRANTABLE FROM (" + " SELECT table_catalog AS TABLE_CAT, table_schema AS TABLE_SCHEM, table_name, column_name," + " grantor, grantee, privilege_type AS PRIVILEGE, is_grantable" + " FROM information_schema.column_privileges"); + if ( PQserverVersion( m_pSettings->pConnection ) < 90200 ) + // information_schema.table_privileges does not fill in default ACLs when no ACL + // assume default ACL is "owner has all privileges" and add it + sSQL.append( + " UNION " + " SELECT current_database() AS TABLE_CAT, pn.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME, a.attname AS column_name," + " ro.rolname AS GRANTOR, rg.rolname AS GRANTEE, p.privilege, 'YES' AS is_grantable" + " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a," + " (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('REFERENCES')) p (privilege)," + " pg_catalog.pg_roles ro," + " ( SELECT oid, rolname FROM pg_catalog.pg_roles" + " UNION ALL" + " VALUES (0::oid, 'PUBLIC')" + " ) AS rg (oid, rolname)," + " pg_catalog.pg_namespace pn" + " WHERE c.relkind IN ('r', 'v') AND c.relacl IS NULL AND pg_has_role(rg.oid, c.relowner, 'USAGE')" + " AND c.relowner=ro.oid AND c.relnamespace = pn.oid AND a.attrelid = c.oid AND a.attnum > 0"); + sSQL.append( + " ) dp," + " (SELECT oid, rolname FROM pg_catalog.pg_roles UNION ALL VALUES (0, 'PUBLIC')) pr" + " WHERE table_schem = ? AND table_name = ? AND column_name LIKE ? AND (dp.grantee = 'PUBLIC' OR pg_has_role(pr.oid, dp.grantee, 'USAGE'))" + " ORDER BY column_name, privilege" ); + + m_getColumnPrivs_stmt = m_origin->prepareStatement( sSQL.makeStringAndClear() ); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getImportedExportedKeys( + const Any& /* primaryCatalog */, + const OUString& primarySchema, + const OUString& primaryTable, + const Any& /* foreignCatalog */, + const OUString& foreignSchema, + const OUString& foreignTable ) +{ + unsigned int i = 0; + if ( ! primarySchema.isEmpty() ) + i |= 0x01; + if ( ! primaryTable.isEmpty() ) + i |= 0x02; + if ( ! foreignSchema.isEmpty() ) + i |= 0x04; + if ( ! foreignTable.isEmpty() ) + i |= 0x08; + + Reference< XPreparedStatement > stmt = m_getReferences_stmt[i]; + Reference< XParameters > param ( stmt, UNO_QUERY_THROW ); + + unsigned int j = 1; + if ( i & 0x01 ) + param->setString( j++, primarySchema ); + if ( i & 0x02 ) + param->setString( j++, primaryTable ); + if ( i & 0x04 ) + param->setString( j++, foreignSchema ); + if ( i & 0x08 ) + param->setString( j++, foreignTable ); + + Reference< XResultSet > rs = stmt->executeQuery(); + + return rs; +} + + +css::uno::Reference< XResultSet > DatabaseMetaData::getImportedKeys( + const css::uno::Any& catalog, + const OUString& schema, + const OUString& table ) +{ + return getImportedExportedKeys(Any(), OUString(), OUString(), catalog, schema, table); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getExportedKeys( + const css::uno::Any& catalog, + const OUString& schema, + const OUString& table ) +{ + return getImportedExportedKeys(catalog, schema, table, Any(), OUString(), OUString()); +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getCrossReference( + const css::uno::Any& primaryCatalog, + const OUString& primarySchema, + const OUString& primaryTable, + const css::uno::Any& foreignCatalog, + const OUString& foreignSchema, + const OUString& foreignTable ) +{ + return getImportedExportedKeys( primaryCatalog, primarySchema, primaryTable, foreignCatalog, foreignSchema, foreignTable ); +} + +namespace +{ + struct TypeInfoByDataTypeSorter + { + bool operator () ( const std::vector< Any > & a, const std::vector< Any > & b ) + { + OUString valueA; + OUString valueB; + a[1 /*DATA_TYPE*/] >>= valueA; + b[1 /*DATA_TYPE*/] >>= valueB; + if( valueB.toInt32() == valueA.toInt32() ) + { + OUString nameA; + OUString nameB; + a[0 /*TYPE_NAME*/] >>= nameA; + b[0 /*TYPE_NAME*/] >>= nameB; + OUString nsA, tnA, nsB, tnB; + + // parse typename into schema and typename + sal_Int32 nIndex=0; + nsA = nameA.getToken(0, '.', nIndex); + if (nIndex<0) + { + tnA = nsA; + nsA.clear(); + } + else + { + tnA = nameA.getToken(0, '.', nIndex); + assert(nIndex < 0); + } + + nIndex=0; + nsB = nameB.getToken(0, '.', nIndex); + if (nIndex<0) + { + tnB = nsB; + nsB.clear(); + } + else + { + tnB = nameB.getToken(0, '.', nIndex); + assert(nIndex < 0); + } + + const int ns_comp = compare_schema(nsA, nsB); + if(ns_comp == 0) + { + if(nsA.isEmpty()) + { + assert(nsB.isEmpty()); + // within each type category, sort privileged choice first + if( tnA == "int4" || tnA == "varchar" || tnA == "char" || tnA == "text") + return true; + if( tnB == "int4" || tnB == "varchar" || tnB == "char" || tnB == "text") + return false; + } + return nameA.compareTo( nameB ) < 0; + } + else + { + return ns_comp < 0; + } + } + + return valueA.toInt32() < valueB.toInt32(); + } + }; + + sal_Int32 calcSearchable( sal_Int32 dataType ) + { + sal_Int32 ret = css::sdbc::ColumnSearch::FULL; + if( css::sdbc::DataType::BINARY == dataType || + css::sdbc::DataType::VARBINARY == dataType || + css::sdbc::DataType::LONGVARBINARY == dataType ) + ret = css::sdbc::ColumnSearch::NONE; + + return ret; + } + + sal_Int32 getMaxScale( sal_Int32 dataType ) + { + // LEM TODO: review, see where used, see JDBC, ... + sal_Int32 ret = 0; + if( dataType == css::sdbc::DataType::NUMERIC ) + ret = 1000; // see pg-docs DataType/numeric +// else if( dataType == DataType::DOUBLE ) +// ret = 308; +// else if( dataType == DataType::FLOAT ) +// ret = + return ret; + } + + OUString construct_full_typename(const OUString &ns, const OUString &tn) + { + if(ns.isEmpty() || ns == "pg_catalog") + return tn; + else + return ns + "." + tn; + } + + void pgTypeInfo2ResultSet( + std::vector< std::vector<Any> > &vec, + const Reference< XResultSet > &rs ) + { + static const sal_Int32 TYPE_NAME = 0; // string Type name + static const sal_Int32 DATA_TYPE = 1; // short SQL data type from java.sql.Types + static const sal_Int32 PRECISION = 2; // long maximum precision + static const sal_Int32 CREATE_PARAMS = 5; // string => parameters used in creating the type (may be NULL ) + static const sal_Int32 NULLABLE = 6; // short ==> can you use NULL for this type? + // - NO_NULLS - does not allow NULL values + // - NULLABLE - allows NULL values + // - NULLABLE_UNKNOWN - nullability unknown + + static const sal_Int32 CASE_SENSITIVE = 7; // boolean==> is it case sensitive + static const sal_Int32 SEARCHABLE = 8; // short ==>; can you use + // "WHERE" based on this type: + // - NONE - No support + // - CHAR - Only supported with WHERE .. LIKE + // - BASIC - Supported except for WHERE .. LIKE + // - FULL - Supported for all WHERE .. + static const sal_Int32 UNSIGNED_ATTRIBUTE = 9; // boolean ==> is it unsigned? + // FIXED_PREC_SCALE = 10; boolean ==> can it be a money value? + static const sal_Int32 AUTO_INCREMENT = 11; // boolean ==> can it be used for + // an auto-increment value? + static const sal_Int32 MINIMUM_SCALE = 13; // short ==> minimum scale supported + static const sal_Int32 MAXIMUM_SCALE = 14; // short ==> maximum scale supported + static const sal_Int32 NUM_PREC_RADIX = 17; // long ==> usually 2 or 10 + + /* not filled so far + 3. LITERAL_PREFIX string ==> prefix used to quote a literal + (may be <NULL/>) + 4. LITERAL_SUFFIX string ==> suffix used to quote a literal + (may be <NULL/>) + 5. CREATE_PARAMS string ==> parameters used in creating the type (may be <NULL/>) + 12. LOCAL_TYPE_NAME string ==> localized version of type name (may be <NULL/>) + 15, SQL_DATA_TYPE long ==> unused + 16. SQL_DATETIME_SUB long ==> unused + */ + Reference< XRow > xRow( rs, UNO_QUERY_THROW ); + while( rs->next() ) + { + std::vector< Any > row(18); + + sal_Int32 dataType =typeNameToDataType(xRow->getString(5),xRow->getString(2)); + sal_Int32 precision = xRow->getString(3).toInt32(); + + if( dataType == css::sdbc::DataType::CHAR || + ( dataType == css::sdbc::DataType::VARCHAR && + xRow->getString(TYPE_NAME+1).equalsIgnoreAsciiCase("varchar") ) ) + { + // reflect varchar as varchar with upper limit ! + //NOTE: the sql spec requires varchar to have an upper limit, however + // in postgresql the upper limit is optional, no limit means unlimited + // length (=1GB). + precision = 0x40000000; // about 1 GB, see character type docs in postgresql + row[CREATE_PARAMS] <<= OUString("length"); + } + else if( dataType == css::sdbc::DataType::NUMERIC ) + { + precision = 1000; + row[CREATE_PARAMS] <<= OUString("length, scale"); + } + + row[TYPE_NAME] <<= construct_full_typename(xRow->getString(6), xRow->getString(1)); + row[DATA_TYPE] <<= OUString::number(dataType); + row[PRECISION] <<= OUString::number( precision ); + sal_Int32 nullable = xRow->getBoolean(4) ? + css::sdbc::ColumnValue::NO_NULLS : + css::sdbc::ColumnValue::NULLABLE; + row[NULLABLE] <<= OUString::number(nullable); + row[CASE_SENSITIVE] <<= OUString::number(1); + row[SEARCHABLE] <<= OUString::number( calcSearchable( dataType ) ); + row[UNSIGNED_ATTRIBUTE] <<= OUString("0"); + if( css::sdbc::DataType::INTEGER == dataType || + css::sdbc::DataType::BIGINT == dataType ) + row[AUTO_INCREMENT] <<= OUString("1"); // TODO + else + row[AUTO_INCREMENT] <<= OUString("0"); // TODO + row[MINIMUM_SCALE] <<= OUString("0"); // TODO: what is this ? + row[MAXIMUM_SCALE] <<= OUString::number( getMaxScale( dataType ) ); + row[NUM_PREC_RADIX] <<= OUString("10"); // TODO: what is this ? + vec.push_back( row ); + } + } +} + + +css::uno::Reference< XResultSet > DatabaseMetaData::getTypeInfo( ) +{ + // Note: Indexes start at 0 (in the API doc, they start at 1) + MutexGuard guard( m_xMutex->GetMutex() ); + + SAL_INFO("connectivity.postgresql", "DatabaseMetaData::getTypeInfo() got called"); + + Reference< XStatement > statement = m_origin->createStatement(); + Reference< XResultSet > rs = statement->executeQuery( + "SELECT pg_type.typname AS typname," //1 + "pg_type.typtype AS typtype," //2 + "pg_type.typlen AS typlen," //3 + "pg_type.typnotnull AS typnotnull," //4 + "pg_type.typname AS typname, " //5 + "pg_namespace.nspname as typns " //6 + "FROM pg_type LEFT JOIN pg_namespace ON pg_type.typnamespace=pg_namespace.oid " + "WHERE pg_type.typtype = 'b' " + "OR pg_type.typtype = 'p'" + ); + + std::vector< std::vector<Any> > vec; + pgTypeInfo2ResultSet( vec, rs ); + + // check for domain types + rs = statement->executeQuery( + "SELECT t1.typname as typname," + "t2.typtype AS typtype," + "t2.typlen AS typlen," + "t2.typnotnull AS typnotnull," + "t2.typname as realtypname, " + "pg_namespace.nspname as typns " + "FROM pg_type as t1 LEFT JOIN pg_type AS t2 ON t1.typbasetype=t2.oid LEFT JOIN pg_namespace ON t1.typnamespace=pg_namespace.oid " + "WHERE t1.typtype = 'd'" ); + pgTypeInfo2ResultSet( vec, rs ); + + std::sort( vec.begin(), vec.end(), TypeInfoByDataTypeSorter() ); + + return new SequenceResultSet( + m_xMutex, + *this, + getStatics().typeinfoColumnNames, + vec, + m_pSettings->tc, + &( getStatics().typeInfoMetaData )); +} + + +css::uno::Reference< XResultSet > DatabaseMetaData::getIndexInfo( + const css::uno::Any& , + const OUString& schema, + const OUString& table, + sal_Bool unique, + sal_Bool ) +{ + //LEM TODO: review + MutexGuard guard( m_xMutex->GetMutex() ); + + /* + 1. TABLE_CAT string -> table catalog (may be NULL ) + 2. TABLE_SCHEM string -> table schema (may be NULL ) + 3. TABLE_NAME string -> table name + 4. NON_UNIQUE boolean -> Can index values be non-unique? + false when TYPE is tableIndexStatistic + 5. INDEX_QUALIFIER string -> index catalog (may be NULL ); + NULL when TYPE is tableIndexStatistic + 6. INDEX_NAME string -> index name; NULL when TYPE is tableIndexStatistic + 7. TYPE short -> index type: + * 0 - this identifies table statistics that are returned + in conjunction with a table's index descriptions + * CLUSTERED - this is a clustered index + * HASHED - this is a hashed index + * OTHER - this is some other style of index + 8. ORDINAL_POSITION short -> column sequence number within index; + zero when TYPE is tableIndexStatistic + 9. COLUMN_NAME string -> column name; NULL when TYPE is tableIndexStatistic + 10. ASC_OR_DESC string -> column sort sequence, "A"= ascending, + "D" = descending, may be NULL if sort sequence + is not supported; NULL when TYPE is tableIndexStatistic + 11. CARDINALITY long -> When TYPE is tableIndexStatistic, then this is + the number of rows in the table; otherwise, it + is the number of unique values in the index. + 12. PAGES long -> When TYPE is tableIndexStatisic then this is + the number of pages used for the table, otherwise + it is the number of pages used for the current index. + 13. FILTER_CONDITION string -> Filter condition, if any. (may be NULL ) + + */ + static const sal_Int32 C_SCHEMA = 1; + static const sal_Int32 C_TABLENAME = 2; + static const sal_Int32 C_INDEXNAME = 3; + static const sal_Int32 C_IS_CLUSTERED = 4; + static const sal_Int32 C_IS_UNIQUE = 5; + // C_IS_PRIMARY = 6 + static const sal_Int32 C_COLUMNS = 7; + + static const sal_Int32 R_TABLE_SCHEM = 1; + static const sal_Int32 R_TABLE_NAME = 2; + static const sal_Int32 R_NON_UNIQUE = 3; + static const sal_Int32 R_INDEX_NAME = 5; + static const sal_Int32 R_TYPE = 6; + static const sal_Int32 R_ORDINAL_POSITION = 7; + static const sal_Int32 R_COLUMN_NAME = 8; + + Reference< XPreparedStatement > stmt = m_origin->prepareStatement( + "SELECT nspname, " // 1 + "pg_class.relname, " // 2 + "class2.relname, " // 3 + "indisclustered, " // 4 + "indisunique, " // 5 + "indisprimary, " // 6 + "indkey " // 7 + "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid " + "WHERE nspname = ? AND pg_class.relname = ?" ); + + Reference< XParameters > param ( stmt, UNO_QUERY_THROW ); + param->setString( 1, schema ); + param->setString( 2, table ); + Reference< XResultSet > rs = stmt->executeQuery(); + Reference< XRow > xRow ( rs, UNO_QUERY_THROW ); + + std::vector< std::vector<Any> > vec; + while( rs->next() ) + { + std::vector< sal_Int32 > columns = parseIntArray( xRow->getString(C_COLUMNS) ); + Reference< XPreparedStatement > columnsStmt = m_origin->prepareStatement( + "SELECT attnum, attname " + "FROM pg_attribute " + " INNER JOIN pg_class ON attrelid = pg_class.oid " + " INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid " + " WHERE pg_namespace.nspname=? AND pg_class.relname=?" ); + Reference< XParameters > paramColumn ( columnsStmt, UNO_QUERY_THROW ); + OUString currentSchema = xRow->getString( C_SCHEMA ); + OUString currentTable = xRow->getString( C_TABLENAME ); + OUString currentIndexName = xRow->getString( C_INDEXNAME ); + bool isNonUnique = ! xRow->getBoolean( C_IS_UNIQUE ); + sal_Int32 indexType = xRow->getBoolean( C_IS_CLUSTERED ) ? + css::sdbc::IndexType::CLUSTERED : + css::sdbc::IndexType::HASHED; + + paramColumn->setString( C_SCHEMA, currentSchema ); + paramColumn->setString( C_TABLENAME, currentTable ); + + Reference< XResultSet > rsColumn = columnsStmt->executeQuery(); + Reference< XRow > rowColumn( rsColumn, UNO_QUERY_THROW ); + while( rsColumn->next() ) + { + auto findIt = std::find( columns.begin(), columns.end(), rowColumn->getInt( 1 ) ); + if( findIt != columns.end() && ( ! isNonUnique || ! unique ) ) + { + std::vector< Any > result( 13 ); + result[R_TABLE_SCHEM] <<= currentSchema; + result[R_TABLE_NAME] <<= currentTable; + result[R_INDEX_NAME] <<= currentIndexName; + result[R_NON_UNIQUE] <<= isNonUnique; + result[R_TYPE] <<= indexType; + result[R_COLUMN_NAME] <<= rowColumn->getString(2); + sal_Int32 nPos = static_cast<sal_Int32>(findIt - columns.begin() +1); // MSVC++ nonsense + result[R_ORDINAL_POSITION] <<= nPos; + vec.push_back( result ); + } + } + } + return new SequenceResultSet( + m_xMutex, *this, getStatics().indexinfoColumnNames, + vec, + m_pSettings->tc ); +} + +sal_Bool DatabaseMetaData::supportsResultSetType( sal_Int32 setType ) +{ + if ( setType == css::sdbc::ResultSetType::SCROLL_SENSITIVE ) + return false; + else + return true; +} + +sal_Bool DatabaseMetaData::supportsResultSetConcurrency( + sal_Int32 setType, sal_Int32 ) +{ + if ( ! supportsResultSetType( setType ) ) + return false; + else + return true; +} + +sal_Bool DatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /* setType */ ) +{ + return true; +} + +sal_Bool DatabaseMetaData::ownDeletesAreVisible( sal_Int32 /* setType */ ) +{ + return true; +} + +sal_Bool DatabaseMetaData::ownInsertsAreVisible( sal_Int32 /* setType */ ) +{ + return true; +} + +sal_Bool DatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::othersDeletesAreVisible( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::othersInsertsAreVisible( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::updatesAreDetected( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::deletesAreDetected( sal_Int32 /* setType */ ) +{ + return false; +} +sal_Bool DatabaseMetaData::insertsAreDetected( sal_Int32 /* setType */ ) +{ + return false; +} + +sal_Bool DatabaseMetaData::supportsBatchUpdates( ) +{ + return true; +} + +css::uno::Reference< XResultSet > DatabaseMetaData::getUDTs( const css::uno::Any&, const OUString&, const OUString&, const css::uno::Sequence< sal_Int32 >& ) +{ + //LEM TODO: implement! See JDBC driver + MutexGuard guard( m_xMutex->GetMutex() ); + return new SequenceResultSet( + m_xMutex, *this, std::vector< OUString >(), std::vector< std::vector< Any > >(), m_pSettings->tc ); +} + +css::uno::Reference< css::sdbc::XConnection > DatabaseMetaData::getConnection() +{ + return m_origin; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx b/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx new file mode 100644 index 000000000..c016886f2 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_databasemetadata.hxx @@ -0,0 +1,240 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_DATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_DATABASEMETADATA_HXX + +#include "pq_connection.hxx" +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> + +#include <cppuhelper/implbase.hxx> + +namespace pq_sdbc_driver +{ + +class DatabaseMetaData : + public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData > +{ + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + ConnectionSettings *m_pSettings; + css::uno::Reference< css::sdbc::XConnection > m_origin; + css::uno::Reference< css::sdbc::XPreparedStatement > m_getIntSetting_stmt; + css::uno::Reference< css::sdbc::XPreparedStatement > m_getReferences_stmt[16]; + css::uno::Reference< css::sdbc::XPreparedStatement > m_getTablePrivs_stmt; + css::uno::Reference< css::sdbc::XPreparedStatement > m_getColumnPrivs_stmt; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getIntSetting(const OUString& settingName); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getMaxIndexKeys(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getMaxNameLength(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Reference< css::sdbc::XResultSet > getImportedExportedKeys( + const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, + const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ); + void init_getReferences_stmt (); + void init_getPrivs_stmt (); + +public: + DatabaseMetaData( + const ::rtl::Reference< comphelper::RefCountedMutex > & reMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings + ); + +public: + // Methods + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override; + virtual OUString SAL_CALL getIdentifierQuoteString( ) override; + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL isCatalogAtStart( ) override; + virtual OUString SAL_CALL getCatalogSeparator( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxStatements( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_driver.cxx b/connectivity/source/drivers/postgresql/pq_driver.cxx new file mode 100644 index 000000000..99571112c --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_driver.cxx @@ -0,0 +1,314 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <comphelper/processfactory.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include "pq_driver.hxx" + +using osl::MutexGuard; + +using com::sun::star::lang::XSingleComponentFactory; +using com::sun::star::lang::XServiceInfo; +using com::sun::star::lang::XComponent; + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::Any; + +using com::sun::star::beans::PropertyValue; + +using com::sun::star::sdbc::XConnection; +using com::sun::star::sdbc::DriverPropertyInfo; + +using com::sun::star::sdbcx::XTablesSupplier; + + +namespace pq_sdbc_driver +{ + +static OUString DriverGetImplementationName() +{ + return "org.openoffice.comp.connectivity.pq.Driver.noext"; +} + +static Sequence< OUString > DriverGetSupportedServiceNames() +{ + return Sequence< OUString > { "com.sun.star.sdbc.Driver" }; +} + +Reference< XConnection > Driver::connect( + const OUString& url,const Sequence< PropertyValue >& info ) +{ + if( ! acceptsURL( url ) ) // XDriver spec tells me to do so ... + return Reference< XConnection > (); + + Sequence< Any > seq ( 2 ); + seq[0] <<= url; + seq[1] <<= info; + return Reference< XConnection> ( + m_smgr->createInstanceWithArgumentsAndContext( + "org.openoffice.comp.connectivity.pq.Connection.noext", + seq, m_ctx ), + UNO_QUERY ); +} + +sal_Bool Driver::acceptsURL( const OUString& url ) +{ + return url.startsWith( "sdbc:postgresql:" ); +} + +Sequence< DriverPropertyInfo > Driver::getPropertyInfo( + const OUString&,const Sequence< PropertyValue >& ) +{ + return Sequence< DriverPropertyInfo > (); +} + +sal_Int32 Driver::getMajorVersion( ) +{ + return PQ_SDBC_MAJOR; +} + + +sal_Int32 Driver::getMinorVersion( ) +{ + return PQ_SDBC_MINOR; +} + + // XServiceInfo +OUString SAL_CALL Driver::getImplementationName() +{ + return DriverGetImplementationName(); +} + +sal_Bool Driver::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > Driver::getSupportedServiceNames() +{ + return DriverGetSupportedServiceNames(); +} + +// XComponent +void Driver::disposing() +{ + +} + + +Reference< XTablesSupplier > Driver::getDataDefinitionByConnection( + const Reference< XConnection >& connection ) +{ + return Reference< XTablesSupplier >( connection , UNO_QUERY ); +} + +Reference< XTablesSupplier > Driver::getDataDefinitionByURL( + const OUString& url, const Sequence< PropertyValue >& info ) +{ + return Reference< XTablesSupplier > ( connect( url, info ), UNO_QUERY ); +} + + +static Reference< XInterface > DriverCreateInstance( const Reference < XComponentContext > & ctx ) +{ + Reference< XInterface > ret = * new Driver( ctx ); + return ret; +} + +namespace { + +class OOneInstanceComponentFactory : + public MutexHolder, + public cppu::WeakComponentImplHelper< XSingleComponentFactory, XServiceInfo > +{ +public: + OOneInstanceComponentFactory( + const OUString & rImplementationName_, + cppu::ComponentFactoryFunc fptr, + const Sequence< OUString > & serviceNames, + const Reference< XComponentContext > & defaultContext) : + cppu::WeakComponentImplHelper< XSingleComponentFactory, XServiceInfo >( m_mutex ), + m_create( fptr ), + m_serviceNames( serviceNames ), + m_implName( rImplementationName_ ), + m_defaultContext( defaultContext ) + { + } + + // XSingleComponentFactory + virtual Reference< XInterface > SAL_CALL createInstanceWithContext( + Reference< XComponentContext > const & xContext ) override; + virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { + return m_implName; + } + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override + { + return cppu::supportsService(this, ServiceName); + } + Sequence< OUString > SAL_CALL getSupportedServiceNames() override + { + return m_serviceNames; + } + + // XComponent + virtual void SAL_CALL disposing() override; + +private: + cppu::ComponentFactoryFunc m_create; + Sequence< OUString > m_serviceNames; + OUString m_implName; + Reference< XInterface > m_theInstance; + Reference< XComponentContext > m_defaultContext; +}; + +} + +Reference< XInterface > OOneInstanceComponentFactory::createInstanceWithArgumentsAndContext( + Sequence< Any > const &, const Reference< XComponentContext > & ctx ) +{ + return createInstanceWithContext( ctx ); +} + +Reference< XInterface > OOneInstanceComponentFactory::createInstanceWithContext( + const Reference< XComponentContext > & ctx ) +{ + if( ! m_theInstance.is() ) + { + // work around the problem in sdbc + Reference< XComponentContext > useCtx = ctx; + if( ! useCtx.is() ) + useCtx = m_defaultContext; + Reference< XInterface > theInstance = m_create( useCtx ); + MutexGuard guard( osl::Mutex::getGlobalMutex() ); + if( ! m_theInstance.is () ) + { + m_theInstance = theInstance; + } + } + return m_theInstance; +} + +void OOneInstanceComponentFactory::disposing() +{ + Reference< XComponent > rComp; + { + MutexGuard guard( osl::Mutex::getGlobalMutex() ); + rComp.set( m_theInstance, UNO_QUERY ); + m_theInstance.clear(); + } + if( rComp.is() ) + rComp->dispose(); +} + +// Reference< XSingleComponentFactory > createOneInstanceComponentFactory( +// cppu::ComponentFactoryFunc fptr, +// OUString const & rImplementationName, +// css::uno::Sequence< OUString > const & rServiceNames, +// rtl_ModuleCount * pModCount = 0 ) +// +// { +// return new OOneInstanceComponentFactory( rImplementationName, fptr , rServiceNames); +// } + +} + +static const struct cppu::ImplementationEntry g_entries[] = +{ + { + pq_sdbc_driver::DriverCreateInstance, pq_sdbc_driver::DriverGetImplementationName, + pq_sdbc_driver::DriverGetSupportedServiceNames, nullptr, + nullptr , 0 + }, + { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } +}; + +extern "C" +{ + +SAL_DLLPUBLIC_EXPORT void * postgresql_sdbc_component_getFactory( + const char * pImplName, void * pServiceManager, void * ) +{ + // need to extract the defaultcontext, because the way, sdbc + // bypasses the servicemanager, does not allow to use the + // XSingleComponentFactory interface ... + void * pRet = nullptr; + Reference< XSingleComponentFactory > xFactory; + Reference< css::lang::XMultiServiceFactory > xSmgr( + static_cast< XInterface * >(pServiceManager), + css::uno::UNO_QUERY_THROW ); + + for( sal_Int32 i = 0 ; g_entries[i].create ; i ++ ) + { + OUString implName = g_entries[i].getImplementationName(); + if( implName.equalsAscii( pImplName ) ) + { + Reference< XComponentContext > defaultContext( + comphelper::getComponentContext( xSmgr ) ); + xFactory = new pq_sdbc_driver::OOneInstanceComponentFactory( + implName, + g_entries[i].create, + g_entries[i].getSupportedServiceNames(), + defaultContext ); + } + } + + if( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + return pRet; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_driver.hxx b/connectivity/source/drivers/postgresql/pq_driver.hxx new file mode 100644 index 000000000..4cd0ee736 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_driver.hxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_DRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_DRIVER_HXX + +#include <osl/mutex.hxx> +#include <sal/macros.h> +#include <cppuhelper/compbase.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> + +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace pq_sdbc_driver +{ + +#define PQ_SDBC_DRIVER_VERSION SAL_STRINGIFY(PQ_SDBC_MAJOR) "." \ + SAL_STRINGIFY(PQ_SDBC_MINOR) "." \ + SAL_STRINGIFY(PQ_SDBC_MICRO) + +struct MutexHolder { osl::Mutex m_mutex; }; +// use this to switch off sdbc support ! +// typedef cppu::WeakComponentImplHelper< +// css::sdbc::XDriver, +// css::lang::XServiceInfo +// > DriverBase ; +typedef cppu::WeakComponentImplHelper< + css::sdbc::XDriver, + css::lang::XServiceInfo, + css::sdbcx::XDataDefinitionSupplier > DriverBase ; +class Driver : public MutexHolder, public DriverBase +{ + css::uno::Reference< css::uno::XComponentContext > m_ctx; + css::uno::Reference< css::lang::XMultiComponentFactory > m_smgr; + +public: + explicit Driver ( const css::uno::Reference < css::uno::XComponentContext > & ctx ) + : DriverBase( m_mutex ), + m_ctx( ctx ), + m_smgr( ctx->getServiceManager() ) + {} + +public: // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( + const OUString& url, + const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( + const OUString& url, + const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + +public: // XServiceInfo + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +public: // XDataDefinitionSupplier + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL + getDataDefinitionByConnection( + const css::uno::Reference< css::sdbc::XConnection >& connection ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL + getDataDefinitionByURL( + const OUString& url, + const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + // XComponent + virtual void SAL_CALL disposing() override; + +}; + + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx new file mode 100644 index 000000000..a75897ccb --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.cxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include "pq_fakedupdateableresultset.hxx" +#include <com/sun/star/sdbc/SQLException.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XResultSetUpdate; +using com::sun::star::sdbc::XRowUpdate; + +namespace pq_sdbc_driver +{ + +FakedUpdateableResultSet::FakedUpdateableResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **pSettings, + PGresult *result, + const OUString &schema, + const OUString &table, + const OUString &aReason ) + : ResultSet( mutex, owner, pSettings, result, schema, table ), + m_aReason( aReason ) +{} + + +css::uno::Any FakedUpdateableResultSet::queryInterface( + const css::uno::Type & reqType ) +{ + Any ret = ResultSet::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< XResultSetUpdate * > ( this ), + static_cast< XRowUpdate * > ( this ) ); + return ret; +} + + +css::uno::Sequence< css::uno::Type > FakedUpdateableResultSet::getTypes() +{ + static cppu::OTypeCollection s_collection( + cppu::UnoType<XResultSetUpdate>::get(), + cppu::UnoType<XRowUpdate>::get(), + ResultSet::getTypes()); + + return s_collection.getTypes(); + +} + +css::uno::Sequence< sal_Int8> FakedUpdateableResultSet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void FakedUpdateableResultSet::insertRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::deleteRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); + } + +void FakedUpdateableResultSet::cancelRowUpdates( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::moveToInsertRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::moveToCurrentRow( ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + + +void FakedUpdateableResultSet::updateNull( sal_Int32 /* columnIndex */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateBoolean( sal_Int32 /* columnIndex */, sal_Bool /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateByte( sal_Int32 /* columnIndex */, sal_Int8 /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateShort( sal_Int32 /* columnIndex */, sal_Int16 /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateInt( sal_Int32 /* columnIndex */, sal_Int32 /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateLong( sal_Int32 /* columnIndex */, sal_Int64 /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateFloat( sal_Int32 /* columnIndex */, float /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateDouble( sal_Int32 /* columnIndex */, double /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateString( sal_Int32 /* columnIndex */, const OUString& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateBytes( sal_Int32 /* columnIndex */, const css::uno::Sequence< sal_Int8 >& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateDate( sal_Int32 /* columnIndex */, const css::util::Date& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateTime( sal_Int32 /* columnIndex */, const css::util::Time& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateTimestamp( sal_Int32 /* columnIndex */, const css::util::DateTime& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +void FakedUpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ ) +{ + throw SQLException( m_aReason, *this, OUString(),1,Any() ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx new file mode 100644 index 000000000..65113344c --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_fakedupdateableresultset.hxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_FAKEDUPDATEABLERESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_FAKEDUPDATEABLERESULTSET_HXX + +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> + +#include "pq_resultset.hxx" + +namespace pq_sdbc_driver +{ +/** necessary to avoid crashes in OOo, when an updateable result set is requested, + but cannot be delivered. + */ +class FakedUpdateableResultSet : + public ResultSet, + public css::sdbc::XResultSetUpdate, + public css::sdbc::XRowUpdate +{ + OUString m_aReason; + +public: + FakedUpdateableResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **pSettings, + PGresult *result, + const OUString &schema, + const OUString &table, + const OUString &aReason ); + +public: // XInterface + virtual void SAL_CALL acquire() throw() override { ResultSet::acquire(); } + virtual void SAL_CALL release() throw() override { ResultSet::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + +public: // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + +}; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx b/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx new file mode 100644 index 000000000..2e3523203 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_preparedstatement.cxx @@ -0,0 +1,737 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include "pq_preparedstatement.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" +#include "pq_statement.hxx" + +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> + + +#include <comphelper/sequence.hxx> + +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <memory> +#include <string.h> + +#include <connectivity/dbconversion.hxx> + +using osl::MutexGuard; + + +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY; + +using com::sun::star::lang::IllegalArgumentException; + +using com::sun::star::sdbc::XCloseable; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XRef; +using com::sun::star::sdbc::XBlob; +using com::sun::star::sdbc::XClob; +using com::sun::star::sdbc::XArray; +using com::sun::star::sdbc::XConnection; +using com::sun::star::sdbc::SQLException; + +using com::sun::star::beans::Property; +using com::sun::star::beans::XPropertySetInfo; + +using namespace dbtools; + +namespace pq_sdbc_driver +{ +static ::cppu::IPropertyArrayHelper & getPreparedStatementPropertyArrayHelper() +{ + static ::cppu::OPropertyArrayHelper arrayHelper( + Sequence<Property>{ + Property( + "CursorName", 0, + ::cppu::UnoType<OUString>::get() , 0 ), + Property( + "EscapeProcessing", 1, + cppu::UnoType<bool>::get() , 0 ), + Property( + "FetchDirection", 2, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "FetchSize", 3, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "MaxFieldSize", 4, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "MaxRows", 5, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "QueryTimeOut", 6, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetConcurrency", 7, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetType", 8, + ::cppu::UnoType<sal_Int32>::get() , 0 )}, + true ); + static ::cppu::IPropertyArrayHelper *pArrayHelper = &arrayHelper; + + return *pArrayHelper; +} + +static bool isOperator( char c ) +{ + static const char * const operators = "<>=()!/&%.,;"; + + const char * w = operators; + while (*w && *w != c) + { + ++w; + } + return *w != 0; +} + +static bool isNamedParameterStart( const OString & o , int index ) +{ + return o[index] == ':' && ( + isWhitespace( o[index-1] ) || isOperator(o[index-1]) ); +} + +static bool isQuoted( const OString & str ) +{ + return str[0] == '"' || str[0] == '\''; +} + +PreparedStatement::PreparedStatement( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< XConnection > & conn, + struct ConnectionSettings *pSettings, + const OString & stmt ) + : PreparedStatement_BASE(refMutex->GetMutex()) + , OPropertySetHelper(PreparedStatement_BASE::rBHelper) + , m_connection(conn) + , m_pSettings(pSettings) + , m_stmt(stmt) + , m_xMutex(refMutex) + , m_multipleResultAvailable(false) + , m_multipleResultUpdateCount(0) + , m_lastOidInserted( InvalidOid ) +{ + m_props[PREPARED_STATEMENT_QUERY_TIME_OUT] <<= sal_Int32(0); + m_props[PREPARED_STATEMENT_MAX_ROWS] <<= sal_Int32(0); + m_props[PREPARED_STATEMENT_RESULT_SET_CONCURRENCY] <<= + css::sdbc::ResultSetConcurrency::READ_ONLY; + m_props[PREPARED_STATEMENT_RESULT_SET_TYPE] <<= + css::sdbc::ResultSetType::SCROLL_INSENSITIVE; + + splitSQL( m_stmt, m_splittedStatement ); + int elements = 0; + for(const OString & str : m_splittedStatement) + { + // ignore quoted strings... + if( ! isQuoted( str ) ) + { + // the ':' cannot be the first or the last part of the + // token, + // the ? cannot be the first part of the token , so we start + // at one + for( int index = 1 ; index < str.getLength() ; index ++ ) + { + if( str[index] == '?' || + isNamedParameterStart( str , index ) + ) + { + elements ++; + } + } + } + } + m_vars = std::vector< OString >( elements ); +} + +PreparedStatement::~PreparedStatement() +{ +} + +void PreparedStatement::checkColumnIndex( sal_Int32 parameterIndex ) +{ + if( parameterIndex < 1 || parameterIndex > static_cast<sal_Int32>(m_vars.size()) ) + { + throw SQLException( + "pq_preparedstatement: parameter index out of range (expected 1 to " + + OUString::number( m_vars.size() ) + + ", got " + OUString::number( parameterIndex ) + + ", statement '" + OStringToOUString( m_stmt, ConnectionSettings::encoding ) + + "')", + *this, OUString(), 1, Any () ); + } +} +void PreparedStatement::checkClosed() +{ + if( ! m_pSettings || ! m_pSettings->pConnection ) + throw SQLException( + "pq_driver: PreparedStatement or connection has already been closed !", + *this, OUString(),1,Any()); +} + +Any PreparedStatement::queryInterface( const Type & rType ) +{ + Any aRet = PreparedStatement_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + + +Sequence< Type > PreparedStatement::getTypes() +{ + static Sequence< Type > collection( + ::comphelper::concatSequences( + OPropertySetHelper::getTypes(), + PreparedStatement_BASE::getTypes())); + + return collection; +} + +Sequence< sal_Int8> PreparedStatement::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void PreparedStatement::close( ) +{ + // let the connection die without acquired mutex ! + Reference< XConnection > r; + Reference< XCloseable > resultSet; + { + MutexGuard guard( m_xMutex->GetMutex() ); + m_pSettings = nullptr; + r = m_connection; + m_connection.clear(); + + resultSet = m_lastResultset; + m_lastResultset.clear(); + } + if( resultSet.is() ) + { + resultSet->close(); + } +} + +void PreparedStatement::raiseSQLException( const char * errorMsg ) +{ + OUStringBuffer buf(128); + buf.append( "pq_driver: "); + buf.append( + OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding ) ); + buf.append( " (caused by statement '" ); + buf.appendAscii( m_executedStatement.getStr() ); + buf.append( "')" ); + OUString error = buf.makeStringAndClear(); + SAL_WARN("connectivity.postgresql", error); + throw SQLException( error, *this, OUString(), 1, Any() ); +} + +Reference< XResultSet > PreparedStatement::executeQuery( ) +{ + if( ! execute( ) ) + { + raiseSQLException( "not a query" ); + } + return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY ); +} + +sal_Int32 PreparedStatement::executeUpdate( ) +{ + if( execute( ) ) + { + raiseSQLException( "not a command" ); + } + return m_multipleResultUpdateCount; +} + +sal_Bool PreparedStatement::execute( ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + OStringBuffer buf( m_stmt.getLength() *2 ); + + std::vector< OString >::size_type vars = 0; + for(const OString & str : m_splittedStatement) + { + // LEM TODO: instead of this manual mucking with SQL + // could we use PQexecParams / PQExecPrepared / ...? + // Only snafu is giving the types of the parameters and + // that it needs $1, $2, etc instead of "?" + +// printf( "Split %d %s\n" , i , str.getStr() ); + if( isQuoted( str ) ) + { + buf.append( str ); + } + else + { + int start = 0,index; + for( index = 1 ; index < str.getLength() ; index ++ ) + { + if( str[index] == '?' ) + { + buf.append( str.getStr()+start, index - start ); + buf.append( m_vars[vars] ); + vars ++; + start =index+1; + } + else + { + if ( isNamedParameterStart( str, index ) ) + { + buf.append( str.getStr()+start, index -start ); + buf.append( m_vars[vars] ); + + // skip to the end of the named parameter + while ( index < str.getLength() + && !( isWhitespace(str[index]) + || isOperator (str[index]))) + { + ++index; + } + start = index; + vars ++; + } + } + } +// if( index +1 >= str.getLength() ) +// { + buf.append( str.getStr() + start, index -start ); +// } + } + } + + m_executedStatement = buf.makeStringAndClear(); + + Reference< XCloseable > lastResultSet = m_lastResultset; + if( lastResultSet.is() ) + lastResultSet->close(); + + m_lastResultset.clear(); + m_lastTableInserted.clear(); + + struct CommandData data; + data.refMutex = m_xMutex; + data.ppSettings = &m_pSettings; + data.pLastOidInserted = &m_lastOidInserted; + data.pLastQuery = &m_lastQuery; + data.pMultipleResultUpdateCount = &m_multipleResultUpdateCount; + data.pMultipleResultAvailable = &m_multipleResultAvailable; + data.pLastTableInserted = &m_lastTableInserted; + data.pLastResultset = &m_lastResultset; + data.owner = *this; + data.tableSupplier.set( m_connection, UNO_QUERY ); + data.concurrency = extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY ); + + return executePostgresCommand( m_executedStatement , &data ); // see pq_statement.cxx +} + +Reference< XConnection > PreparedStatement::getConnection( ) +{ + Reference< XConnection > ret; + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + ret = m_connection; + } + return ret; +} + + +void PreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = OString( "NULL" ); +} + +void PreparedStatement::setObjectNull( + sal_Int32 parameterIndex, sal_Int32, const OUString& ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = OString( "NULL" ); +} + + +void PreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + if( x ) + m_vars[parameterIndex-1] = OString( "'t'" ); + else + m_vars[parameterIndex-1] = OString( "'f'" ); +} + +void PreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x ) +{ + setInt(parameterIndex,x); +} + +void PreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) +{ + setInt(parameterIndex, x ); +} + +void PreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) +{ +// printf( "setString %d %d\n ", parameterIndex, x); + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = "'" + OString::number(x) + "'"; +} + +void PreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = "'" + OString::number(x) + "'"; +} + +void PreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = "'" + OString::number(x) + "'"; +} + +void PreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + m_vars[parameterIndex-1] = "'" + OString::number(x) + "'"; +} + +void PreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ +// printf( "setString %d %s\n ", parameterIndex, +// OUStringToOString( x , RTL_TEXTENCODING_ASCII_US ).getStr()); + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + OStringBuffer buf( 20 ); + buf.append( "'" ); + OString y = OUStringToOString( x, ConnectionSettings::encoding ); + buf.ensureCapacity( y.getLength() * 2 + 2 ); + int len = PQescapeString( const_cast<char*>(buf.getStr())+1, y.getStr() , y.getLength() ); + buf.setLength( 1 + len ); + buf.append( "'" ); + m_vars[parameterIndex-1] = buf.makeStringAndClear(); +} + +void PreparedStatement::setBytes( + sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + checkClosed(); + checkColumnIndex( parameterIndex ); + size_t len; + struct Free { void operator ()(void * p) const { free(p); } }; + std::unique_ptr<unsigned char, Free> escapedString( + PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len)); + if( ! escapedString ) + { + throw SQLException( + "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string", + *this, OUString(), 1, Any() ); + } + m_vars[parameterIndex-1] + = "'" + rtl::OStringView(reinterpret_cast<char *>(escapedString.get()), len -1) + "'"; +} + + +void PreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x ) +{ + setString( parameterIndex, DBTypeConversion::toDateString( x ) ); +} + +void PreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x ) +{ + setString( parameterIndex, DBTypeConversion::toTimeString( x ) ); +} + +void PreparedStatement::setTimestamp( + sal_Int32 parameterIndex, const css::util::DateTime& x ) +{ + setString( parameterIndex, DBTypeConversion::toDateTimeString( x ) ); +} + +void PreparedStatement::setBinaryStream( + sal_Int32, + const Reference< css::io::XInputStream >&, + sal_Int32 ) +{ + throw SQLException( + "pq_preparedstatement: setBinaryStream not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setCharacterStream( + sal_Int32, + const Reference< css::io::XInputStream >&, + sal_Int32 ) +{ + throw SQLException( + "pq_preparedstatement: setCharacterStream not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) +{ + if( ! implSetObject( this, parameterIndex, x )) + { + throw SQLException( + "pq_preparedstatement::setObject: can't convert value of type " + x.getValueTypeName(), + *this, OUString(), 1, Any () ); + } +} + +void PreparedStatement::setObjectWithInfo( + sal_Int32 parameterIndex, + const Any& x, + sal_Int32 targetSqlType, + sal_Int32 ) +{ + if( css::sdbc::DataType::DECIMAL == targetSqlType || + css::sdbc::DataType::NUMERIC == targetSqlType ) + { + double myDouble = 0.0; + OUString myString; + if( x >>= myDouble ) + { + myString = OUString::number( myDouble ); + } + else + { + x >>= myString; + } + if( myString.isEmpty() ) + { + throw SQLException( + "pq_preparedstatement::setObjectWithInfo: can't convert value of type " + + x.getValueTypeName() + " to type DECIMAL or NUMERIC", + *this, OUString(), 1, Any () ); + } + + setString( parameterIndex, myString ); + } + else + { + setObject( parameterIndex, x ); + } + +} + +void PreparedStatement::setRef( + sal_Int32, + const Reference< XRef >& ) +{ + throw SQLException( + "pq_preparedstatement: setRef not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setBlob( + sal_Int32, + const Reference< XBlob >& ) +{ + throw SQLException( + "pq_preparedstatement: setBlob not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setClob( + sal_Int32, + const Reference< XClob >& ) +{ + throw SQLException( + "pq_preparedstatement: setClob not implemented", + *this, OUString(), 1, Any () ); +} + +void PreparedStatement::setArray( + sal_Int32 parameterIndex, + const Reference< XArray >& x ) +{ + setString( parameterIndex, array2String( x->getArray( nullptr ) ) ); +} + +void PreparedStatement::clearParameters( ) +{ + MutexGuard guard(m_xMutex->GetMutex() ); + m_vars = std::vector< OString >( m_vars.size() ); +} + +Any PreparedStatement::getWarnings( ) +{ + return Any(); +} + +void PreparedStatement::clearWarnings( ) +{ +} + +Reference< css::sdbc::XResultSetMetaData > PreparedStatement::getMetaData() +{ + Reference< css::sdbc::XResultSetMetaData > ret; + Reference< css::sdbc::XResultSetMetaDataSupplier > supplier( m_lastResultset, UNO_QUERY ); + if( supplier.is() ) + ret = supplier->getMetaData(); + return ret; +} + +::cppu::IPropertyArrayHelper & PreparedStatement::getInfoHelper() +{ + return getPreparedStatementPropertyArrayHelper(); +} + + +sal_Bool PreparedStatement::convertFastPropertyValue( + Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) +{ + bool bRet; + rOldValue = m_props[nHandle]; + switch( nHandle ) + { + case PREPARED_STATEMENT_CURSOR_NAME: + { + OUString val; + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + case PREPARED_STATEMENT_ESCAPE_PROCESSING: + { + bool val(false); + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + case PREPARED_STATEMENT_FETCH_DIRECTION: + case PREPARED_STATEMENT_FETCH_SIZE: + case PREPARED_STATEMENT_MAX_FIELD_SIZE: + case PREPARED_STATEMENT_MAX_ROWS: + case PREPARED_STATEMENT_QUERY_TIME_OUT: + case PREPARED_STATEMENT_RESULT_SET_CONCURRENCY: + case PREPARED_STATEMENT_RESULT_SET_TYPE: + { + sal_Int32 val; + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + default: + { + throw IllegalArgumentException( + "pq_statement: Invalid property handle (" + + OUString::number( nHandle ) + ")", + *this, 2 ); + } + } + return bRet; +} + + +void PreparedStatement::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle,const Any& rValue ) +{ + m_props[nHandle] = rValue; +} + +void PreparedStatement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + rValue = m_props[nHandle]; +} + +Reference < XPropertySetInfo > PreparedStatement::getPropertySetInfo() +{ + return OPropertySetHelper::createPropertySetInfo( getPreparedStatementPropertyArrayHelper() ); +} + +void PreparedStatement::disposing() +{ + close(); +} + + +Reference< XResultSet > PreparedStatement::getResultSet( ) +{ + return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY ); +} +sal_Int32 PreparedStatement::getUpdateCount( ) +{ + return m_multipleResultUpdateCount; +} +sal_Bool PreparedStatement::getMoreResults( ) +{ + Reference< XCloseable > lastResultSet = m_lastResultset; + if( lastResultSet.is() ) + lastResultSet->close(); + m_multipleResultUpdateCount = -1; + return false; +} + +Reference< XResultSet > PreparedStatement::getGeneratedValues( ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + return getGeneratedValuesFromLastInsert( + m_pSettings, m_connection, m_lastOidInserted, m_lastTableInserted, m_lastQuery ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx b/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx new file mode 100644 index 000000000..01eb2441f --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_preparedstatement.hxx @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_PREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_PREPAREDSTATEMENT_HXX +#include <vector> + +#include <libpq-fe.h> + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> + +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> + +#include "pq_connection.hxx" +namespace pq_sdbc_driver +{ + +static const sal_Int32 PREPARED_STATEMENT_CURSOR_NAME = 0; +static const sal_Int32 PREPARED_STATEMENT_ESCAPE_PROCESSING = 1; +static const sal_Int32 PREPARED_STATEMENT_FETCH_DIRECTION = 2; +static const sal_Int32 PREPARED_STATEMENT_FETCH_SIZE = 3; +static const sal_Int32 PREPARED_STATEMENT_MAX_FIELD_SIZE = 4; +static const sal_Int32 PREPARED_STATEMENT_MAX_ROWS = 5; +static const sal_Int32 PREPARED_STATEMENT_QUERY_TIME_OUT = 6; +static const sal_Int32 PREPARED_STATEMENT_RESULT_SET_CONCURRENCY = 7; +static const sal_Int32 PREPARED_STATEMENT_RESULT_SET_TYPE = 8; + +#define PREPARED_STATEMENT_SIZE 9 + +typedef ::cppu::WeakComponentImplHelper< css::sdbc::XPreparedStatement, + css::sdbc::XParameters, + css::sdbc::XCloseable, + css::sdbc::XWarningsSupplier, + css::sdbc::XMultipleResults, + css::sdbc::XGeneratedResultSet, + css::sdbc::XResultSetMetaDataSupplier + > PreparedStatement_BASE; +class PreparedStatement : public PreparedStatement_BASE, + public cppu::OPropertySetHelper +{ +private: + css::uno::Any m_props[PREPARED_STATEMENT_SIZE]; + css::uno::Reference< css::sdbc::XConnection > m_connection; + ConnectionSettings *m_pSettings; + css::uno::Reference< css::sdbc::XCloseable > m_lastResultset; + OString m_stmt; + OString m_executedStatement; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + std::vector< OString > m_vars; + std::vector< OString > m_splittedStatement; + bool m_multipleResultAvailable; + sal_Int32 m_multipleResultUpdateCount; + sal_Int32 m_lastOidInserted; + OUString m_lastTableInserted; + OString m_lastQuery; + +public: + /** + * @param ppConnection The piece of memory, pConnection points to, is accessible + * as long as a reference to parameter con is held. + */ + PreparedStatement( const rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection> & con, + struct ConnectionSettings *pSettings, + const OString &stmt ); + + virtual ~PreparedStatement() override; +public: // XInterface + virtual void SAL_CALL acquire() throw() override { PreparedStatement_BASE::acquire(); } + virtual void SAL_CALL release() throw() override { PreparedStatement_BASE::release(); } + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & reqType ) override; + +public: // XCloseable + virtual void SAL_CALL close( ) override; + +public: // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery() override; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + virtual sal_Bool SAL_CALL execute( ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; +public: // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( + sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( + sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( + sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( + sal_Int32 parameterIndex, + const css::uno::Reference< css::io::XInputStream >& x, + sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( + sal_Int32 parameterIndex, + const css::uno::Reference< css::io::XInputStream >& x, + sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( + sal_Int32 parameterIndex, + const css::uno::Any& x, + sal_Int32 targetSqlType, + sal_Int32 scale ) override; + virtual void SAL_CALL setRef( + sal_Int32 parameterIndex, + const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( + sal_Int32 parameterIndex, + const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( + sal_Int32 parameterIndex, + const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( + sal_Int32 parameterIndex, + const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + +public: // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // OPropertySetHelper + virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + + void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + // XPropertySet + css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + +public: // XGeneratedResultSet + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + getGeneratedValues( ) override; + +public: // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + +public: // XResultSetMetaDataSupplier (is required by framework (see + // dbaccess/source/core/api/preparedstatement.cxx::getMetaData() ) + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + +public: // OComponentHelper + virtual void SAL_CALL disposing() override; + +private: + void checkColumnIndex( sal_Int32 parameterIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkClosed(); + /// @throws css::sdbc::SQLException + void raiseSQLException( const char * errorMsg ); +// PGresult *pgExecute( OString *pQuery ); +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_resultset.cxx b/connectivity/source/drivers/postgresql/pq_resultset.cxx new file mode 100644 index 000000000..556bae92d --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_resultset.cxx @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include "pq_resultset.hxx" +#include "pq_resultsetmetadata.hxx" + +#include <connectivity/dbexception.hxx> + +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + + +using osl::MutexGuard; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; + +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XResultSetMetaData; + + +namespace pq_sdbc_driver +{ + +void ResultSet::checkClosed() +{ + if( ! m_result ) + { + throw SQLException( "pq_resultset: already closed", + *this, OUString(), 1, Any() ); + } + + if( ! m_ppSettings || ! *m_ppSettings || ! (*m_ppSettings)->pConnection ) + { + throw SQLException( "pq_resultset: statement has been closed already", + *this, OUString(), 1, Any() ); + } + +} + +ResultSet::ResultSet( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< XInterface > & owner, + ConnectionSettings **ppSettings, + PGresult * result, + const OUString &schema, + const OUString &table) + : BaseResultSet( + refMutex, owner, PQntuples( result ), + PQnfields( result ),(*ppSettings)->tc ), + m_result( result ), + m_schema( schema ), + m_table( table ), + m_ppSettings( ppSettings ) +{ + // LEM TODO: shouldn't these things be inherited from the statement or something like that? + // Positioned update/delete not supported, so no cursor name + // Fetch direction and size are cursor-specific things, so not used now. + // Fetch size not set + m_props[ BASERESULTSET_FETCH_DIRECTION ] <<= css::sdbc::FetchDirection::UNKNOWN; + // No escape processing for now + m_props[ BASERESULTSET_ESCAPE_PROCESSING ] <<= false; + // Bookmarks not implemented for now + m_props[ BASERESULTSET_IS_BOOKMARKABLE ] <<= false; + m_props[ BASERESULTSET_RESULT_SET_CONCURRENCY ] <<= css::sdbc::ResultSetConcurrency::READ_ONLY; + m_props[ BASERESULTSET_RESULT_SET_TYPE ] <<= css::sdbc::ResultSetType::SCROLL_INSENSITIVE; +} + + +Any ResultSet::getValue( sal_Int32 columnIndex ) +{ + Any ret; + if( PQgetisnull( m_result, m_row, columnIndex -1 ) ) + { + m_wasNull = true; + } + else + { + m_wasNull = false; + ret <<= OUString( + PQgetvalue( m_result, m_row , columnIndex -1 ) , + PQgetlength( m_result, m_row , columnIndex -1 ) , + ConnectionSettings::encoding ); + + } + return ret; +} + +ResultSet::~ResultSet() +{} + +void ResultSet::close( ) +{ + Reference< XInterface > owner; + { + MutexGuard guard( m_xMutex->GetMutex() ); + if( m_result ) + { + PQclear(m_result ); + m_result = nullptr; + m_row = -1; + } + owner = m_owner; + m_owner.clear(); + } +} + +Reference< XResultSetMetaData > ResultSet::getMetaData( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + return new ResultSetMetaData( + m_xMutex, this, this, m_ppSettings, m_result, m_schema, m_table ); +} + +sal_Int32 ResultSet::findColumn( const OUString& columnName ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + sal_Int32 res = PQfnumber( m_result, + OUStringToOString( columnName, ConnectionSettings::encoding ).getStr()); + /* PQfnumber return -1 for not found, which is what we want + * other than that we use col number as 1-based not 0-based */ + if(res >= 0) + { + res += 1; + } + else + { + ::dbtools::throwInvalidColumnException( columnName, *this ); + assert(false); + } + return res; +} + +static bool isNumber( const char * data, sal_Int32 len ) +{ + bool ret = false; + if( len ) + { + ret = true; + for( int i = 0 ; i < len ; i ++ ) + { + if( ( data[i] >= '0' && data[i] <= '9' ) || + data[i] == '-' || data[i] == '+' || data[i] == '.' || data[i] == ',' ) + { + if( data[i] == '-' && i != 0 && i != len-1 ) + { + // no number, maybe a date + ret = false; + break; + } + } + else + { + ret = false; + break; + } + } + } + return ret; +} + +static bool isInteger( const char * data, sal_Int32 len ) +{ + bool ret = false; + if( len ) + { + ret = true; + for( int i = 0 ; i < len ; i ++ ) + { + if( ( data[i] >= '0' && data[i] <= '9' ) || + data[i] == '-' || data[i] == '+' ) + { + if( data[i] == '-' && i != 0 && i != len-1 ) + { + // no number, maybe a date + ret = false; + break; + } + } + else + { + ret = false; + break; + } + } + } + return ret; +} + +static bool isDate( const char * data, sal_Int32 len ) +{ + return 10 == len && + '-' == data[4] && + '-' == data[7] && + isInteger( &(data[0]),4 ) && + isInteger( &(data[5]),2) && + isInteger( &(data[8]),2 ); +} + +static bool isTime( const char * data, sal_Int32 len ) +{ + return 8 == len && + ':' == data[2] && + ':' == data[5] && + isInteger( &(data[0]),2 ) && + isInteger( &(data[3]),2) && + isInteger( &(data[6]),2 ); + +} + +static bool isTimestamp( const char * data, sal_Int32 len ) +{ + return len == 19 && isDate( data, 10) && isTime( &(data[11]),8 ); +} + +sal_Int32 ResultSet::guessDataType( sal_Int32 column ) +{ + // we don't look into more than 100 rows ... + sal_Int32 ret = css::sdbc::DataType::INTEGER; + + int maxRows = std::min<sal_Int32>( m_rowCount, 100 ); + for( int i = 0 ; i < maxRows ; i ++ ) + { + if( ! PQgetisnull( m_result, i , column-1 ) ) + { + const char * p = PQgetvalue( m_result, i , column -1 ); + int len = PQgetlength( m_result, i , column -1 ); + + if( css::sdbc::DataType::INTEGER == ret ) + { + if( ! isInteger( p,len ) ) + ret = css::sdbc::DataType::NUMERIC; + } + if( css::sdbc::DataType::NUMERIC == ret ) + { + if( ! isNumber( p,len ) ) + { + ret = css::sdbc::DataType::DATE; + } + } + if( css::sdbc::DataType::DATE == ret ) + { + if( ! isDate( p,len ) ) + { + ret = css::sdbc::DataType::TIME; + } + } + if( css::sdbc::DataType::TIME == ret ) + { + if( ! isTime( p,len ) ) + { + ret = css::sdbc::DataType::TIMESTAMP; + } + } + if( css::sdbc::DataType::TIMESTAMP == ret ) + { + if( ! isTimestamp( p,len ) ) + { + ret = css::sdbc::DataType::LONGVARCHAR; + break; + } + } + } + } + return ret; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_resultset.hxx b/connectivity/source/drivers/postgresql/pq_resultset.hxx new file mode 100644 index 000000000..4b2bb6f41 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_resultset.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_RESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_RESULTSET_HXX + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> + +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include "pq_connection.hxx" +#include "pq_baseresultset.hxx" + +namespace pq_sdbc_driver +{ + +class ResultSet : public BaseResultSet +{ +protected: + PGresult *m_result; + OUString m_schema; + OUString m_table; + ConnectionSettings **m_ppSettings; + +protected: + /** mutex should be locked before called + */ + virtual void checkClosed() override; + + /** unchecked, acquire mutex before calling + */ + virtual css::uno::Any getValue( sal_Int32 columnIndex ) override; + +public: + ResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **pSettings, + PGresult *result, + const OUString &schema, + const OUString &table ); + virtual ~ResultSet() override; + +public: // XCloseable + virtual void SAL_CALL close( ) override; + +public: // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + +public: // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + +public: + sal_Int32 guessDataType( sal_Int32 column ); +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx new file mode 100644 index 000000000..0452324a1 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <rtl/ustrbuf.hxx> + +#include "pq_resultsetmetadata.hxx" +#include "pq_resultset.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> + +#include <string.h> + +using osl::MutexGuard; + + +using com::sun::star::uno::Any; +using com::sun::star::uno::Exception; +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY; + + +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbcx::XColumnsSupplier; +using com::sun::star::sdbcx::XTablesSupplier; + +using com::sun::star::beans::XPropertySet; +using com::sun::star::container::XNameAccess; + + +namespace pq_sdbc_driver +{ + +// struct ColumnMetaData +// { +// OUString tableName; +// OUString schemaTableName; +// OUString typeName; +// css::sdbc::DataType type; +// sal_Int32 precision; +// sal_Int32 scale; +// sal_Bool isCurrency; +// sal_Bool isNullable; +// sal_Bool isAutoIncrement; +// sal_Bool isReadOnly; +// sal_Bool isSigned; +// }; + +// is not exported by the postgres header +const static int PQ_VARHDRSZ = sizeof( sal_Int32 ); + +static void extractPrecisionAndScale( sal_Int32 atttypmod, sal_Int32 *precision, sal_Int32 *scale ) +{ + if( atttypmod < PQ_VARHDRSZ ) + { + *precision = 0; + *scale = 0; + } + else + { + if( atttypmod & 0xffff0000 ) + { + *precision = ( ( atttypmod - PQ_VARHDRSZ ) >> 16 ) & 0xffff; + *scale = (atttypmod - PQ_VARHDRSZ ) & 0xffff; + } + else + { + *precision = atttypmod - PQ_VARHDRSZ; + *scale = 0; + } + } +} + +ResultSetMetaData::ResultSetMetaData( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XResultSet > & origin, + ResultSet * pResultSet, + ConnectionSettings **ppSettings, + PGresult const *pResult, + const OUString &schemaName, + const OUString &tableName ) : + m_xMutex( refMutex ), + m_ppSettings( ppSettings ), + m_origin( origin ), + m_tableName( tableName ), + m_schemaName( schemaName ), + m_colDesc( PQnfields( pResult ) ), + m_pResultSet( pResultSet ), + m_checkedForTable( false ), + m_checkedForTypes( false ), + m_colCount( PQnfields( pResult ) ) +{ + + // extract all needed information from the result object, so that we don't + // need it anymore after this call ! + for( int col = 0; col < m_colCount ; col ++ ) + { + sal_Int32 size = PQfsize( pResult, col ); + size = -1 == size ? 25 : size; + m_colDesc[col].displaySize = size; + + extractPrecisionAndScale( + PQfmod( pResult, col ), + & ( m_colDesc[col].precision ), + & ( m_colDesc[col].scale ) ); + char *name = PQfname( pResult, col ); + m_colDesc[col].name = OUString( name, strlen(name) , ConnectionSettings::encoding ); + m_colDesc[col].typeOid = PQftype( pResult, col ); + m_colDesc[col].type = css::sdbc::DataType::LONGVARCHAR; + } +} + +void ResultSetMetaData::checkForTypes() +{ + if( m_checkedForTypes ) + return; + + Reference< XStatement > stmt = + extractConnectionFromStatement( m_origin->getStatement() )->createStatement(); + DisposeGuard guard( stmt ); + OUStringBuffer buf(128); + buf.append( "SELECT oid, typname, typtype FROM pg_type WHERE "); + for( int i = 0 ; i < m_colCount ; i ++ ) + { + if( i > 0 ) + buf.append( " OR " ); + int oid = m_colDesc[i].typeOid; + buf.append( "oid=" ); + buf.append( static_cast<sal_Int32>(oid) ); + } + Reference< XResultSet > rs = stmt->executeQuery( buf.makeStringAndClear() ); + Reference< XRow > xRow( rs, UNO_QUERY ); + while( rs->next() ) + { + Oid oid = xRow->getInt( 1 ); + OUString typeName = xRow->getString( 2 ); + OUString typType = xRow->getString( 3 ); + + sal_Int32 type = typeNameToDataType( typeName, typType ); + + for( sal_Int32 j = 0; j < m_colCount ; j ++ ) + { + if( m_colDesc[j].typeOid == oid ) + { + m_colDesc[j].typeName = typeName; + m_colDesc[j].type = type; + } + } + } + m_checkedForTypes = true; +} + +void ResultSetMetaData::checkTable() +{ + if( m_checkedForTable ) + return; + + m_checkedForTable = true; + if( !m_tableName.getLength() ) + return; + + Reference< css::container::XNameAccess > tables = (*m_ppSettings)->tables; + if( ! tables.is() ) + { + + Reference< XTablesSupplier > supplier( + extractConnectionFromStatement( m_origin->getStatement() ), UNO_QUERY); + if( supplier.is() ) + tables = supplier->getTables(); + } + if( tables.is() ) + { + const OUString name (getTableName ( 1 )); + const OUString schema (getSchemaName( 1 )); + const OUString composedName( schema.isEmpty() ? name : (schema + "." + name) ); + tables->getByName( composedName ) >>= m_table; + } +} + +sal_Int32 ResultSetMetaData::getIntColumnProperty( const OUString & name, int index, int def ) +{ + sal_Int32 ret = def; // give defensive answers, when data is not available + try + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( index ); + Reference< XPropertySet > set = getColumnByIndex( index ); + + if( set.is() ) + { + set->getPropertyValue( name ) >>= ret; + } + } + catch( css::uno::Exception & ) + { + } + return ret; +} + +bool ResultSetMetaData::getBoolColumnProperty( const OUString & name, int index, bool def ) +{ + bool ret = def; + try + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( index ); + Reference< XPropertySet > set = getColumnByIndex( index ); + if( set.is() ) + { + set->getPropertyValue( name ) >>= ret; + } + } + catch( css::uno::Exception & ) + { + } + + return ret; +} + +Reference< css::beans::XPropertySet > ResultSetMetaData::getColumnByIndex( int index ) +{ + Reference< XPropertySet > ret; + checkTable(); + if( m_table.is() ) + { + OUString columnName = getColumnName( index ); + Reference< XColumnsSupplier > supplier( m_table, UNO_QUERY ); + if( supplier.is() ) + { + Reference< XNameAccess > columns = supplier->getColumns(); + if( columns.is() && columns->hasByName( columnName ) ) + { + columns->getByName( columnName ) >>= ret; + } + } + } + return ret; +} + +// Methods +sal_Int32 ResultSetMetaData::getColumnCount( ) +{ + return m_colCount; +} + +sal_Bool ResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + + bool ret = getBoolColumnProperty( getStatics().IS_AUTO_INCREMENT, column, false ); + return ret; +} + +sal_Bool ResultSetMetaData::isCaseSensitive( sal_Int32 ) +{ + return true; // ??? hmm, numeric types or +} + +sal_Bool ResultSetMetaData::isSearchable( sal_Int32 ) +{ + return true; // mmm, what types are not searchable ? +} + +sal_Bool ResultSetMetaData::isCurrency( sal_Int32 column ) +{ + return getBoolColumnProperty( getStatics().IS_CURRENCY, column, false ); +} + +sal_Int32 ResultSetMetaData::isNullable( sal_Int32 column ) +{ + return getIntColumnProperty( + getStatics().IS_NULLABLE, column, css::sdbc::ColumnValue::NULLABLE_UNKNOWN ); +} + +sal_Bool ResultSetMetaData::isSigned( sal_Int32 ) +{ + return true; +} + +sal_Int32 ResultSetMetaData::getColumnDisplaySize( sal_Int32 column ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + return m_colDesc[column-1].displaySize; +} + +OUString ResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + return getColumnName( column); +} + +OUString ResultSetMetaData::getColumnName( sal_Int32 column ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + + return m_colDesc[column-1].name; +} + +OUString ResultSetMetaData::getSchemaName( sal_Int32 ) +{ + return m_schemaName; +} + +sal_Int32 ResultSetMetaData::getPrecision( sal_Int32 column ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + return m_colDesc[column-1].precision; +} + +sal_Int32 ResultSetMetaData::getScale( sal_Int32 column ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + return m_colDesc[column-1].scale; +} + +OUString ResultSetMetaData::getTableName( sal_Int32 ) +{ +// LEM TODO This is very fishy... Should probably return the table to which that column belongs! + return m_tableName; +} + +OUString ResultSetMetaData::getCatalogName( sal_Int32 ) +{ + // can do this through XConnection.getCatalog() ! + return OUString(); +} +sal_Int32 ResultSetMetaData::getColumnType( sal_Int32 column ) +{ + int ret = getIntColumnProperty( getStatics().TYPE, column, -100 ); + if( -100 == ret ) + { + checkForTypes(); + if( css::sdbc::DataType::LONGVARCHAR == m_colDesc[column-1].type && m_pResultSet ) + m_colDesc[column-1].type = m_pResultSet->guessDataType( column ); + ret = m_colDesc[column-1].type; + } + return ret; +} + +OUString ResultSetMetaData::getColumnTypeName( sal_Int32 column ) +{ + OUString ret; // give defensive answers, when data is not available + try + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkColumnIndex( column ); + Reference< XPropertySet > set = getColumnByIndex( column ); + + if( set.is() ) + { + set->getPropertyValue( getStatics().TYPE_NAME ) >>= ret; + } + else + { + checkForTypes(); + ret = m_colDesc[column-1].typeName; + } + } + catch( css::uno::Exception & ) + { + } + return ret; +} + + +sal_Bool ResultSetMetaData::isReadOnly( sal_Int32 ) +{ + return false; +} + +sal_Bool ResultSetMetaData::isWritable( sal_Int32 column ) +{ + return ! isReadOnly( column ); // what's the sense if this method ? +} + +sal_Bool ResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + return isWritable(column); // uhh, now it becomes really esoteric... +} +OUString ResultSetMetaData::getColumnServiceName( sal_Int32 ) +{ + return OUString(); +} + +void ResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex) +{ + if( columnIndex < 1 || columnIndex > m_colCount ) + { + throw SQLException( + "pq_resultsetmetadata: index out of range (expected 1 to " + + OUString::number( m_colCount ) + ", got " + OUString::number( columnIndex ), + *this, OUString(), 1, Any() ); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx new file mode 100644 index 000000000..2c1b5e5e5 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_resultsetmetadata.hxx @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_RESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_RESULTSETMETADATA_HXX +#include <vector> + +#include "pq_connection.hxx" + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <cppuhelper/implbase.hxx> + +namespace pq_sdbc_driver +{ + +struct ColDesc +{ + OUString name; + sal_Int32 precision; + sal_Int32 scale; + sal_Int32 displaySize; + Oid typeOid; + OUString typeName; + sal_Int32 type; +}; + +class ResultSet; + +class ResultSetMetaData : + public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData > +{ + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + ConnectionSettings **m_ppSettings; + css::uno::Reference< css::sdbc::XResultSet > m_origin; + css::uno::Reference< css::beans::XPropertySet > m_table; + OUString m_tableName; + OUString m_schemaName; + std::vector< ColDesc > m_colDesc; + ResultSet *m_pResultSet; + + bool m_checkedForTable; + bool m_checkedForTypes; + + sal_Int32 m_colCount; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex( sal_Int32 columnIndex ); + void checkTable(); + void checkForTypes(); + css::uno::Reference< css::beans::XPropertySet > getColumnByIndex( int index ); + + sal_Int32 getIntColumnProperty( const OUString & name, int index, int def ); + bool getBoolColumnProperty( const OUString & name, int index, bool def ); + +public: + ResultSetMetaData( + const ::rtl::Reference< comphelper::RefCountedMutex > & reMutex, + const css::uno::Reference< css::sdbc::XResultSet > & origin, + ResultSet *pResultSet, + ConnectionSettings **pSettings, + PGresult const *pResult, + const OUString &schemaName, + const OUString &tableName ); + +public: + // Methods + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx b/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx new file mode 100644 index 000000000..02030729a --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_sequenceresultset.cxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + + +#include "pq_sequenceresultset.hxx" +#include "pq_sequenceresultsetmetadata.hxx" + +#include <connectivity/dbexception.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +using com::sun::star::sdbc::XResultSetMetaData; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Any; + +namespace pq_sdbc_driver +{ + +void SequenceResultSet::checkClosed() +{ + // we never close :o) +} + + +Any SequenceResultSet::getValue( sal_Int32 columnIndex ) +{ + m_wasNull = ! m_data[m_row][columnIndex -1 ].hasValue(); + return m_data[m_row][columnIndex -1 ]; +} + +SequenceResultSet::SequenceResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + const std::vector< OUString > &colNames, + const std::vector< std::vector< Any > > &data, + const Reference< css::script::XTypeConverter > & tc, + const ColumnMetaDataVector *pVec) : + BaseResultSet( mutex, owner, data.size(), colNames.size(), tc ), + m_data(data ), + m_columnNames( colNames ) +{ + if( pVec ) + { + m_meta = new SequenceResultSetMetaData( *pVec, m_columnNames.size() ); + } +} + +SequenceResultSet::~SequenceResultSet() +{ + +} + +void SequenceResultSet::close( ) +{ + // a noop +} + +Reference< XResultSetMetaData > SAL_CALL SequenceResultSet::getMetaData( ) +{ + if( ! m_meta.is() ) + { + // Oh no, not again + throw css::sdbc::SQLException( + "pq_sequenceresultset: no meta supported ", *this, + // I did not find "IM001" in a specific standard, + // but it seems to be used by other systems (such as ODBC) + // and some parts of LibreOffice special-case it. + "IM001", 1, Any() ); + } + return m_meta; +} + + +sal_Int32 SAL_CALL SequenceResultSet::findColumn( + const OUString& columnName ) +{ + // no need to guard, as all members are readonly ! + for( int i = 0 ;i < m_fieldCount ; i ++ ) + { + if( columnName == m_columnNames[i] ) + { + return i+1; + } + } + ::dbtools::throwInvalidColumnException( columnName, *this ); + assert(false); + return 0; // Never reached +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx b/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx new file mode 100644 index 000000000..3b97e24a3 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_sequenceresultset.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_SEQUENCERESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_SEQUENCERESULTSET_HXX + +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> + +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include "pq_connection.hxx" +#include "pq_baseresultset.hxx" +#include "pq_statics.hxx" + +namespace pq_sdbc_driver +{ + +class SequenceResultSet : public BaseResultSet +{ +protected: + std::vector< std::vector< css::uno::Any > > m_data; + + std::vector< OUString > m_columnNames; + css::uno::Reference< css::sdbc::XResultSetMetaData > m_meta; + +protected: + /** mutex should be locked before called + */ + virtual void checkClosed() override; + + /** unchecked, acquire mutex before calling + */ + virtual css::uno::Any getValue( sal_Int32 columnIndex ) override; + +public: + SequenceResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + const std::vector< OUString > &colNames, + const std::vector< std::vector< css::uno::Any > > &data, + const css::uno::Reference< css::script::XTypeConverter > &tc, + const ColumnMetaDataVector *pVec = nullptr); + virtual ~SequenceResultSet() override; + +public: // XCloseable + virtual void SAL_CALL close( ) override; + +public: // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + +public: // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx new file mode 100644 index 000000000..d45ffc0a6 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.cxx @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 200? by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include "pq_sequenceresultsetmetadata.hxx" + +#include <com/sun/star/sdbc/SQLException.hpp> + +using com::sun::star::uno::Any; + +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +SequenceResultSetMetaData::SequenceResultSetMetaData( + const ColumnMetaDataVector &metaDataVector, + int colCount ) : + m_columnData( metaDataVector ), + m_colCount( colCount ) +{ +} + + +// Methods +sal_Int32 SequenceResultSetMetaData::getColumnCount( ) +{ + return m_colCount; +} + +sal_Bool SequenceResultSetMetaData::isAutoIncrement( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].isAutoIncrement; +} + +sal_Bool SequenceResultSetMetaData::isCaseSensitive( sal_Int32 /* column */ ) +{ + + return true; // ??? hmm, numeric types or +} + +sal_Bool SequenceResultSetMetaData::isSearchable( sal_Int32 /* column */ ) +{ + return true; // mmm, what types are not searchable ? +} + +sal_Bool SequenceResultSetMetaData::isCurrency( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].isCurrency; +} + +sal_Int32 SequenceResultSetMetaData::isNullable( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].isNullable ? 1 : 0; +} + +sal_Bool SequenceResultSetMetaData::isSigned( sal_Int32 /* column */ ) +{ + return true; +} + +sal_Int32 SequenceResultSetMetaData::getColumnDisplaySize( sal_Int32 /* column */ ) +{ + return 50; +} + +OUString SequenceResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].columnName; +} + +OUString SequenceResultSetMetaData::getColumnName( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].columnName; +} + +OUString SequenceResultSetMetaData::getSchemaName( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].schemaTableName; +} + + +sal_Int32 SequenceResultSetMetaData::getPrecision( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].precision; +} + +sal_Int32 SequenceResultSetMetaData::getScale( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].scale; +} + +OUString SequenceResultSetMetaData::getTableName( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].tableName; +} + +OUString SequenceResultSetMetaData::getCatalogName( sal_Int32 /* column */ ) +{ + // can do this through XConnection.getCatalog() ! + return OUString(); +} +sal_Int32 SequenceResultSetMetaData::getColumnType( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].type; +} + +OUString SequenceResultSetMetaData::getColumnTypeName( sal_Int32 column ) +{ + checkColumnIndex( column ); + return m_columnData[column-1].typeName; +} + + +sal_Bool SequenceResultSetMetaData::isReadOnly( sal_Int32 /* column */ ) +{ + return false; +} + +sal_Bool SequenceResultSetMetaData::isWritable( sal_Int32 column ) +{ + return ! isReadOnly( column ); // what's the sense if this method ? +} + +sal_Bool SequenceResultSetMetaData::isDefinitelyWritable( sal_Int32 column ) +{ + return isWritable(column); // uhh, now it becomes really esoteric... +} +OUString SequenceResultSetMetaData::getColumnServiceName( sal_Int32 /* column */ ) +{ + return OUString(); +} + +void SequenceResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex) +{ + if( columnIndex < 1 || columnIndex > m_colCount ) + { + throw SQLException( + "pq_sequenceresultsetmetadata: index out of range (expected 1 to " + + OUString::number( m_colCount ) + + ", got " + OUString::number( columnIndex ), + *this, OUString(), 1, Any() ); + } +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx new file mode 100644 index 000000000..2bba06aa7 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_sequenceresultsetmetadata.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 200? by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_SEQUENCERESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_SEQUENCERESULTSETMETADATA_HXX + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> + +#include "pq_connection.hxx" +#include "pq_statics.hxx" + +namespace pq_sdbc_driver +{ + class SequenceResultSetMetaData : + public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData > + { + ColumnMetaDataVector m_columnData; + sal_Int32 m_colCount; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex( sal_Int32 columnIndex ); + + public: + SequenceResultSetMetaData( + const ColumnMetaDataVector &vec, + int colCount ); + + public: + // Methods + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_SEQUENCERESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_statement.cxx b/connectivity/source/drivers/postgresql/pq_statement.cxx new file mode 100644 index 000000000..dd7ab576b --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_statement.cxx @@ -0,0 +1,891 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include "pq_statement.hxx" +#include "pq_fakedupdateableresultset.hxx" +#include "pq_updateableresultset.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +#include <osl/time.h> + +#include <rtl/ustrbuf.hxx> +#include <rtl/strbuf.hxx> + +#include <comphelper/sequence.hxx> + +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> + +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> + +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> + +#include <string.h> + +using osl::MutexGuard; + + +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::UNO_QUERY; + +using com::sun::star::lang::IllegalArgumentException; + +using com::sun::star::sdbc::XCloseable; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XPreparedStatement; +using com::sun::star::sdbc::XParameters; +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XConnection; +using com::sun::star::sdbc::SQLException; + +using com::sun::star::sdbcx::XColumnsSupplier; +using com::sun::star::sdbcx::XKeysSupplier; + +using com::sun::star::beans::Property; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::beans::XPropertySet; + +using com::sun::star::container::XNameAccess; +using com::sun::star::container::XEnumerationAccess; +using com::sun::star::container::XEnumeration; +using com::sun::star::container::XIndexAccess; + +namespace pq_sdbc_driver +{ +static ::cppu::IPropertyArrayHelper & getStatementPropertyArrayHelper() +{ + static ::cppu::OPropertyArrayHelper arrayHelper( + Sequence<Property>{ + Property( + "CursorName", 0, + ::cppu::UnoType<OUString>::get() , 0 ), + Property( + "EscapeProcessing", 1, + cppu::UnoType<bool>::get() , 0 ), + Property( + "FetchDirection", 2, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "FetchSize", 3, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "MaxFieldSize", 4, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "MaxRows", 5, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "QueryTimeOut", 6, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetConcurrency", 7, + ::cppu::UnoType<sal_Int32>::get() , 0 ), + Property( + "ResultSetType", 8, + ::cppu::UnoType<sal_Int32>::get() , 0 )}, + true ); + + return arrayHelper; +} + +Statement::Statement( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< XConnection > & conn, + struct ConnectionSettings *pSettings ) + : Statement_BASE( refMutex->GetMutex() ) + , OPropertySetHelper( Statement_BASE::rBHelper ) + , m_connection( conn ) + , m_pSettings( pSettings ) + , m_xMutex( refMutex ) + , m_multipleResultAvailable(false) + , m_multipleResultUpdateCount(0) + , m_lastOidInserted(InvalidOid) +{ + m_props[STATEMENT_QUERY_TIME_OUT] <<= sal_Int32(0); + m_props[STATEMENT_MAX_ROWS] <<= sal_Int32(0); + m_props[STATEMENT_RESULT_SET_CONCURRENCY] <<= + css::sdbc::ResultSetConcurrency::READ_ONLY; + m_props[STATEMENT_RESULT_SET_TYPE] <<= + css::sdbc::ResultSetType::SCROLL_INSENSITIVE; +} + +Statement::~Statement() +{ +} + +void Statement::checkClosed() +{ + if( ! m_pSettings || ! m_pSettings->pConnection ) + throw SQLException( + "pq_driver: Statement or connection has already been closed !", + *this, OUString(),1,Any()); +} + +Any Statement::queryInterface( const Type & rType ) +{ + Any aRet = Statement_BASE::queryInterface(rType); + return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType); +} + + +Sequence< Type > Statement::getTypes() +{ + static Sequence< Type > collection( + ::comphelper::concatSequences( + OPropertySetHelper::getTypes(), + Statement_BASE::getTypes())); + + return collection; +} + +Sequence< sal_Int8> Statement::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void Statement::close( ) +{ + // let the connection die without acquired mutex ! + Reference< XConnection > r; + Reference< XCloseable > resultSet; + { + MutexGuard guard( m_xMutex->GetMutex() ); + m_pSettings = nullptr; + r = m_connection; + m_connection.clear(); + + resultSet = m_lastResultset; + m_lastResultset.clear(); + } + if( resultSet.is() ) + { + resultSet->close(); + } + +} + +void Statement::raiseSQLException( + const OUString & sql, const char * errorMsg ) +{ + OUString error = "pq_driver: " + + OUString( errorMsg, strlen(errorMsg), ConnectionSettings::encoding ) + + " (caused by statement '" + sql + "')"; + SAL_WARN("connectivity.postgresql", error); + throw SQLException( error, *this, OUString(), 1, Any() ); +} + +Reference< XResultSet > Statement::executeQuery(const OUString& sql ) +{ + if( ! execute( sql ) ) + { + raiseSQLException( sql, "not a query" ); + } + return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY ); +} + +sal_Int32 Statement::executeUpdate( const OUString& sql ) +{ + if( execute( sql ) ) + { + raiseSQLException( sql, "not a command" ); + } + return m_multipleResultUpdateCount; +} + +/// @throws SQLException +static void raiseSQLException( + const Reference< XInterface> & owner, + const OString & sql, + const char * errorMsg, + const char *errorType = nullptr ) +{ + OUStringBuffer buf(128); + buf.append( "pq_driver: "); + if( errorType ) + { + buf.append( "[" ); + buf.appendAscii( errorType ); + buf.append( "]" ); + } + buf.append( + OUString( errorMsg, strlen(errorMsg) , ConnectionSettings::encoding ) ); + buf.append( " (caused by statement '" ); + buf.append( OStringToOUString( sql, ConnectionSettings::encoding ) ); + buf.append( "')" ); + OUString error = buf.makeStringAndClear(); + SAL_WARN("connectivity.postgresql", error); + throw SQLException( error, owner, OUString(), 1, Any() ); +} + + +// returns the elements of the primary key of the given table +// static Sequence< Reference< css::beans::XPropertySet > > lookupKeys( +static std::vector< OUString > lookupKeys( + const Reference< css::container::XNameAccess > &tables, + const OUString & table, + OUString *pSchema, + OUString *pTable) +{ + std::vector< OUString > ret; + Reference< XKeysSupplier > keySupplier; + Statics & st = getStatics(); + + if( tables->hasByName( table ) ) + tables->getByName( table ) >>= keySupplier; + else if( -1 == table.indexOf( '.' ) ) + { + // it wasn't a fully qualified name. Now need to skip through all tables. + Reference< XEnumerationAccess > enumerationAccess( tables, UNO_QUERY ); + + Reference< css::container::XEnumeration > enumeration = + enumerationAccess->createEnumeration(); + while( enumeration->hasMoreElements() ) + { + Reference< XPropertySet > set; + enumeration->nextElement() >>= set; + OUString name; +// OUString schema; + + if( set->getPropertyValue( st.NAME ) >>= name ) + { +// printf( "searching %s %s\n", +// OUStringToOString( schema, RTL_TEXTENCODING_ASCII_US ).getStr(), +// OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() ); + if( name == table ) + { + + if( keySupplier.is() ) + { + // is ambiguous, as I don't know postgresql searchpath, + // I can't continue here, as I may write to a different table + keySupplier.clear(); + SAL_INFO("connectivity.postgresql", "Can't offer updateable result set because table " << name << " is duplicated, add schema to resolve ambiguity"); + break; + } + keySupplier.set( set, UNO_QUERY ); + } + } + } + } + else + { + SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " is unknown)"); + } + + if( keySupplier.is() ) + { + Reference< XPropertySet > set( keySupplier, UNO_QUERY ); + set->getPropertyValue( getStatics().NAME ) >>= *pTable; + set->getPropertyValue( getStatics().SCHEMA_NAME ) >>= *pSchema; + set.clear(); + + Reference< XEnumerationAccess > keys ( keySupplier->getKeys(), UNO_QUERY ); + Reference< XEnumeration > enumeration = keys->createEnumeration(); + while( enumeration->hasMoreElements() ) + { + enumeration->nextElement() >>= set; + sal_Int32 keyType = 0; + if( (set->getPropertyValue( st.TYPE ) >>= keyType ) && + keyType == css::sdbcx::KeyType::PRIMARY ) + { + Reference< XColumnsSupplier > columns( set, UNO_QUERY ); + Reference< XIndexAccess > indexAccess( columns->getColumns(), UNO_QUERY ); + + int length = indexAccess->getCount(); + ret.resize( length ); +// printf( "primary key for Table %s is ", +// OUStringToOString( table, RTL_TEXTENCODING_ASCII_US ).getStr() ); + for( int i = 0 ; i < length ; i ++ ) + { + indexAccess->getByIndex( i ) >>= set; + OUString name; + set->getPropertyValue( st.NAME ) >>= name; + ret[i] = name; +// printf( "%s," , OUStringToOString( name, RTL_TEXTENCODING_ASCII_US ).getStr() ); + } +// printf( "\n" ); + } + } + if( ret.empty() ) + { + SAL_INFO("connectivity.postgresql", "Can't offer updateable result set ( table " << table << " does not have a primary key)"); + } + } + return ret; +} + +bool executePostgresCommand( const OString & cmd, struct CommandData *data ) +{ + ConnectionSettings *pSettings = *(data->ppSettings); + + sal_Int32 duration = osl_getGlobalTimer(); + PGresult *result = PQexec( pSettings->pConnection, cmd.getStr() ); + duration = osl_getGlobalTimer() - duration; + if( ! result ) + raiseSQLException( + data->owner, cmd, PQerrorMessage( pSettings->pConnection ) ); + + ExecStatusType state = PQresultStatus( result ); + *(data->pLastOidInserted) = 0; + data->pLastTableInserted->clear(); + *(data->pLastQuery) = cmd; + + bool ret = false; + switch( state ) + { + case PGRES_COMMAND_OK: + { + *(data->pMultipleResultUpdateCount) = atoi( PQcmdTuples( result ) ); + *(data->pMultipleResultAvailable) = false; + + // in case an oid value is available, we retrieve it + *(data->pLastOidInserted) = PQoidValue( result ); + + // in case it was a single insert, extract the name of the table, + // otherwise the table name is empty + *(data->pLastTableInserted) = + extractTableFromInsert( OStringToOUString( cmd, ConnectionSettings::encoding ) ); + + OString strMain = "executed command '" + cmd + "' successfully ('" + OString::number(*( data->pMultipleResultUpdateCount )) + + "), duration=" + OString::number(duration) + "ms"; + + OString strOption; + if( *(data->pLastOidInserted) ) + { + strOption += ", usedOid=" + OString::number( *(data->pLastOidInserted) ) + ", diagnosedTable=" + + OUStringToOString(*data->pLastTableInserted, ConnectionSettings::encoding); + } + SAL_INFO("connectivity.postgresql", strMain + strOption); + PQclear( result ); + break; + } + case PGRES_TUPLES_OK: // success + { + // In case it is a single table, it has a primary key and all columns + // belonging to the primary key are in the result set, allow updateable result sets + // otherwise, don't + OUString table, schema; + std::vector< OString > vec; + tokenizeSQL( cmd, vec ); + OUString sourceTable = + OStringToOUString( + extractSingleTableFromSelect( vec ), ConnectionSettings::encoding ); + + if( data->concurrency == + css::sdbc::ResultSetConcurrency::UPDATABLE ) + { + OString aReason; + if( sourceTable.getLength() ) + { + std::vector< OUString > sourceTableKeys = lookupKeys( + pSettings->tables.is() ? + pSettings->tables : data->tableSupplier->getTables() , + sourceTable, + &schema, + &table); + + // check, whether the columns are in the result set (required !) + int i; + for( i = 0 ; i < static_cast<int>(sourceTableKeys.size()) ; i ++ ) + { + if( -1 == PQfnumber( + result, + OUStringToOString( sourceTableKeys[i] , + ConnectionSettings::encoding ).getStr()) ) + { + break; + } + } + + if( !sourceTableKeys.empty() && i == static_cast<int>(sourceTableKeys.size()) ) + { + *(data->pLastResultset) = + UpdateableResultSet::createFromPGResultSet( + data->refMutex, data->owner, data->ppSettings, result, + schema, table,sourceTableKeys ); + } + else if( ! table.getLength() ) + { + aReason = "can't support updateable resultset, because a single table in the " + "WHERE part of the statement could not be identified (" + cmd + "."; + } + else if( !sourceTableKeys.empty() ) + { + OStringBuffer buf( 128 ); + buf.append( "can't support updateable resultset for table " ); + buf.append( OUStringToOString( schema, ConnectionSettings::encoding ) ); + buf.append( "." ); + buf.append( OUStringToOString( table, ConnectionSettings::encoding ) ); + buf.append( ", because resultset does not contain a part of the primary key ( column " ); + buf.append( OUStringToOString( sourceTableKeys[i], ConnectionSettings::encoding ) ); + buf.append( " is missing )" ); + aReason = buf.makeStringAndClear(); + } + else + { + + aReason = "can't support updateable resultset for table " + + OUStringToOString( schema, ConnectionSettings::encoding ) + "." + + OUStringToOString( table, ConnectionSettings::encoding ) + + ", because resultset table does not have a primary key "; + } + } + else + { + SAL_WARN("connectivity.postgresql", "can't support updateable result for selects with multiple tables (" << cmd << ")"); + } + if( ! (*(data->pLastResultset)).is() ) + { + SAL_WARN("connectivity.postgresql", aReason); + + // TODO: How to react here correctly ? + // remove this piece of code + *(data->pLastResultset) = + new FakedUpdateableResultSet( + data->refMutex, data->owner, + data->ppSettings,result, schema, table, + OStringToOUString( aReason, ConnectionSettings::encoding) ); + } + + } + else if( sourceTable.getLength() > 0) + { + splitConcatenatedIdentifier( sourceTable, &schema, &table ); + } + + sal_Int32 returnedRows = PQntuples( result ); + if( ! data->pLastResultset->is() ) + *(data->pLastResultset) = + Reference< XCloseable > ( + new ResultSet( + data->refMutex, data->owner, + data->ppSettings,result, schema, table ) ); + *(data->pMultipleResultAvailable) = true; + ret = true; + SAL_INFO("connectivity.postgresql", "executed query '" << cmd << "' successfully, duration=" << duration << "ms, returnedRows=" << returnedRows << "."); + break; + } + case PGRES_EMPTY_QUERY: + case PGRES_COPY_OUT: + case PGRES_COPY_IN: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: + case PGRES_FATAL_ERROR: + default: + raiseSQLException( + data->owner, cmd, PQresultErrorMessage( result ) , PQresStatus( state ) ); + } + return ret; + +} + +static Sequence< OUString > getPrimaryKeyColumnNames( + const Reference< XConnection > & connection, const OUString &schemaName, const OUString &tableName ) +{ + Sequence< OUString > ret; + + Int2StringMap mapIndex2Name; + fillAttnum2attnameMap( mapIndex2Name, connection, schemaName, tableName ); + + // retrieve the primary key ... + Reference< XPreparedStatement > stmt = connection->prepareStatement( + "SELECT conkey " // 7 + "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid " + "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid " + "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'" ); + DisposeGuard guard( stmt ); + Reference< XParameters > paras( stmt, UNO_QUERY ); + paras->setString( 1 , tableName ); + paras->setString( 2 , schemaName ); + Reference< XResultSet > rs = stmt->executeQuery(); + Reference< XRow > xRow( rs , UNO_QUERY ); + + if( rs->next() ) + { + ret = convertMappedIntArray2StringArray( mapIndex2Name, string2intarray(xRow->getString( 1 ) ) ); + } + return ret; +} + +static void getAutoValues( + String2StringMap & result, + const Reference< XConnection > & connection, + const OUString &schemaName, + const OUString & tableName, + ConnectionSettings *pConnectionSettings ) +{ + OUString strDefaultValue = getColExprForDefaultSettingVal(pConnectionSettings); + Reference< XPreparedStatement > stmt = connection->prepareStatement( + "SELECT pg_attribute.attname, " + strDefaultValue + + "FROM pg_class, pg_namespace, pg_attribute " + "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND " + "pg_attribute.attnum = pg_attrdef.adnum " + "WHERE pg_attribute.attrelid = pg_class.oid AND " + "pg_class.relnamespace = pg_namespace.oid AND " + "pg_namespace.nspname = ? AND " + // LEM TODO: this is weird; why "LIKE" and not "="? + // Most probably gives problems if tableName contains '%' + "pg_class.relname LIKE ? AND " + + strDefaultValue + " != ''" + ); + DisposeGuard guard( stmt ); + Reference< XParameters > paras( stmt, UNO_QUERY ); + paras->setString( 1 , schemaName ); + paras->setString( 2 , tableName ); + Reference< XResultSet > rs = stmt->executeQuery(); + Reference< XRow > xRow( rs , UNO_QUERY ); + + while( rs->next() ) + { + result[ OUStringToOString( xRow->getString( 1 ), RTL_TEXTENCODING_ASCII_US) ] = + OUStringToOString( xRow->getString(2), RTL_TEXTENCODING_ASCII_US ); + } +} + +Reference< XResultSet > getGeneratedValuesFromLastInsert( + ConnectionSettings *pConnectionSettings, + const Reference< XConnection > &connection, + sal_Int32 nLastOid, + const OUString & lastTableInserted, + const OString & lastQuery ) +{ + Reference< XResultSet > ret; + OUString query; + OUString schemaName, tableName; + splitConcatenatedIdentifier( + lastTableInserted, &schemaName, &tableName ); + + if( nLastOid && lastTableInserted.getLength() ) + { + OUStringBuffer buf( 128 ); + buf.append( "SELECT * FROM " ); + if( schemaName.getLength() ) + bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings ); + else + bufferQuoteIdentifier( buf, lastTableInserted, pConnectionSettings ); + buf.append( " WHERE oid = " ); + buf.append( nLastOid ); + query = buf.makeStringAndClear(); + } + else if ( lastTableInserted.getLength() && lastQuery.getLength() ) + { + // extract nameValue Pairs + String2StringMap namedValues; + extractNameValuePairsFromInsert( namedValues, lastQuery ); + + // debug ... +// OStringBuffer buf( 128); +// buf.append( "extracting name/value from '" ); +// buf.append( lastQuery.getStr() ); +// buf.append( "' to [" ); +// for( String2StringMap::iterator ii = namedValues.begin() ; ii != namedValues.end() ; ++ii ) +// { +// buf.append( ii->first.getStr() ); +// buf.append( "=" ); +// buf.append( ii->second.getStr() ); +// buf.append( "," ); +// } +// buf.append( "]\n" ); +// printf( "%s", buf.makeStringAndClear() ); + + // TODO: make also unqualified tables names work here. Have a look at 2.8.3. The Schema Search Path + // in postgresql doc + + const Sequence< OUString > keyColumnNames = getPrimaryKeyColumnNames( connection, schemaName, tableName ); + if( keyColumnNames.hasElements() ) + { + OUStringBuffer buf( 128 ); + buf.append( "SELECT * FROM " ); + bufferQuoteQualifiedIdentifier(buf, schemaName, tableName, pConnectionSettings ); + buf.append( " WHERE " ); + bool bAdditionalCondition = false; + String2StringMap autoValues; + for( OUString const & columnNameUnicode : keyColumnNames ) + { + OUString value; + OString columnName = OUStringToOString( columnNameUnicode, ConnectionSettings::encoding ); + bool bColumnMatchNamedValue = false; + for (auto const& namedValue : namedValues) + { + if( columnName.equalsIgnoreAsciiCase( namedValue.first ) ) + { + value = OStringToOUString( namedValue.second , ConnectionSettings::encoding ); + bColumnMatchNamedValue = true; + break; + } + } + + // check, if a column of the primary key was not inserted explicitly, + if( !bColumnMatchNamedValue ) + { + if( autoValues.empty() ) + { + getAutoValues( autoValues, connection, schemaName, tableName, pConnectionSettings ); + } + // this could mean, that the column is a default or auto value, check this ... + bool bColumnMatchAutoValue = false; + for (auto const& autoValue : autoValues) + { + if( columnName.equalsIgnoreAsciiCase( autoValue.first ) ) + { + // it is indeed an auto value. + value = OStringToOUString(autoValue.second, RTL_TEXTENCODING_ASCII_US ); + // check, whether it is a sequence + + if( autoValue.second.startsWith("nextval(") ) + { + // retrieve current sequence value: + OUStringBuffer myBuf(128 ); + myBuf.append( "SELECT currval(" ); + myBuf.appendAscii( &(autoValue.second.getStr()[8])); + value = querySingleValue( connection, myBuf.makeStringAndClear() ); + } + bColumnMatchAutoValue = true; + break; + } + } + if( !bColumnMatchAutoValue ) + { + // it even was no autovalue, no sense to continue as we can't query the + // inserted row + buf.truncate(); + break; + } + } + + if( bAdditionalCondition ) + buf.append( " AND " ); + bufferQuoteIdentifier( buf, columnNameUnicode, pConnectionSettings ); + buf.append( " = " ); + buf.append( value ); + bAdditionalCondition = true; + } + query = buf.makeStringAndClear(); + } + } + + if( query.getLength() ) + { + Reference< css::sdbc::XStatement > stmt = connection->createStatement(); + ret = stmt->executeQuery( query ); + } + + return ret; + +} + +sal_Bool Statement::execute( const OUString& sql ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + OString cmd = OUStringToOString( sql, m_pSettings ); + + Reference< XCloseable > lastResultSetHolder = m_lastResultset; + if( lastResultSetHolder.is() ) + lastResultSetHolder->close(); + + m_lastResultset.clear(); + m_lastTableInserted.clear(); + + struct CommandData data; + data.refMutex = m_xMutex; + data.ppSettings = &m_pSettings; + data.pLastOidInserted = &m_lastOidInserted; + data.pLastQuery = &m_lastQuery; + data.pMultipleResultUpdateCount = &m_multipleResultUpdateCount; + data.pMultipleResultAvailable = &m_multipleResultAvailable; + data.pLastTableInserted = &m_lastTableInserted; + data.pLastResultset = &m_lastResultset; + data.owner = *this; + data.tableSupplier.set( m_connection, UNO_QUERY ); + data.concurrency = + extractIntProperty( this, getStatics().RESULT_SET_CONCURRENCY ); + return executePostgresCommand( cmd , &data ); +} + +Reference< XConnection > Statement::getConnection( ) +{ + Reference< XConnection > ret; + { + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + ret = m_connection; + } + return ret; +} + + +Any Statement::getWarnings( ) +{ + return Any(); +} + +void Statement::clearWarnings( ) +{ +} + +Reference< css::sdbc::XResultSetMetaData > Statement::getMetaData() +{ + Reference< css::sdbc::XResultSetMetaData > ret; + Reference< css::sdbc::XResultSetMetaDataSupplier > supplier( m_lastResultset, UNO_QUERY ); + if( supplier.is() ) + ret = supplier->getMetaData(); + return ret; +} + + +::cppu::IPropertyArrayHelper & Statement::getInfoHelper() +{ + return getStatementPropertyArrayHelper(); +} + + +sal_Bool Statement::convertFastPropertyValue( + Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) +{ + rOldValue = m_props[nHandle]; + bool bRet; + switch( nHandle ) + { + case STATEMENT_CURSOR_NAME: + { + OUString val; + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + case STATEMENT_ESCAPE_PROCESSING: + { + bool val(false); + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + case STATEMENT_FETCH_DIRECTION: + case STATEMENT_FETCH_SIZE: + case STATEMENT_MAX_FIELD_SIZE: + case STATEMENT_MAX_ROWS: + case STATEMENT_QUERY_TIME_OUT: + case STATEMENT_RESULT_SET_CONCURRENCY: + case STATEMENT_RESULT_SET_TYPE: + { + sal_Int32 val; + bRet = ( rValue >>= val ); + rConvertedValue <<= val; + break; + } + default: + { + throw IllegalArgumentException( + "pq_statement: Invalid property handle (" + + OUString::number( nHandle ) + ")", + *this, 2 ); + } + } + return bRet; +} + + +void Statement::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle,const Any& rValue ) +{ + m_props[nHandle] = rValue; +} + +void Statement::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + rValue = m_props[nHandle]; +} + +Reference < XPropertySetInfo > Statement::getPropertySetInfo() +{ + return OPropertySetHelper::createPropertySetInfo( getStatementPropertyArrayHelper() ); +} + + +Reference< XResultSet > Statement::getResultSet( ) +{ + return Reference< XResultSet > ( m_lastResultset, css::uno::UNO_QUERY ); +} + +sal_Int32 Statement::getUpdateCount( ) +{ + return m_multipleResultUpdateCount; +} + +sal_Bool Statement::getMoreResults( ) +{ + // The PostgreSQL C interface always returns a single result, + // so we will never have multiple ones. + // Implicitly close the open resultset (if any) as per spec, + // and setup to signal "no more result, neither as resultset, + // nor as update count". + Reference< XCloseable > lastResultSetHolder = m_lastResultset; + if( lastResultSetHolder.is() ) + lastResultSetHolder->close(); + m_multipleResultUpdateCount = -1; + return false; +} + + +void Statement::disposing() +{ + close(); +} + +Reference< XResultSet > Statement::getGeneratedValues( ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + return getGeneratedValuesFromLastInsert( + m_pSettings, m_connection, m_lastOidInserted, m_lastTableInserted, m_lastQuery ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_statement.hxx b/connectivity/source/drivers/postgresql/pq_statement.hxx new file mode 100644 index 000000000..e53c203af --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_statement.hxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_STATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_STATEMENT_HXX +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/component.hxx> + +#include <libpq-fe.h> + +#include "pq_connection.hxx" +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> + +namespace pq_sdbc_driver +{ + +static const sal_Int32 STATEMENT_CURSOR_NAME = 0; +static const sal_Int32 STATEMENT_ESCAPE_PROCESSING = 1; +static const sal_Int32 STATEMENT_FETCH_DIRECTION = 2; +static const sal_Int32 STATEMENT_FETCH_SIZE = 3; +static const sal_Int32 STATEMENT_MAX_FIELD_SIZE = 4; +static const sal_Int32 STATEMENT_MAX_ROWS = 5; +static const sal_Int32 STATEMENT_QUERY_TIME_OUT = 6; +static const sal_Int32 STATEMENT_RESULT_SET_CONCURRENCY = 7; +static const sal_Int32 STATEMENT_RESULT_SET_TYPE = 8; + +#define STATEMENT_SIZE 9 + +typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement, + css::sdbc::XCloseable, + css::sdbc::XWarningsSupplier, + css::sdbc::XMultipleResults, + css::sdbc::XGeneratedResultSet, + css::sdbc::XResultSetMetaDataSupplier + > Statement_BASE; + +class Statement : public Statement_BASE, + public cppu::OPropertySetHelper +{ +private: + css::uno::Any m_props[STATEMENT_SIZE]; + css::uno::Reference< css::sdbc::XConnection > m_connection; + ConnectionSettings *m_pSettings; + css::uno::Reference< css::sdbc::XCloseable > m_lastResultset; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + bool m_multipleResultAvailable; + sal_Int32 m_multipleResultUpdateCount; + sal_Int32 m_lastOidInserted; + OUString m_lastTableInserted; + OString m_lastQuery; + +public: + /** + * @param ppConnection The piece of memory, pConnection points to, is accessible + * as long as a reference to parameter con is held. + */ + Statement( const rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection> & con, + struct ConnectionSettings *pSettings ); + + virtual ~Statement() override; +public: // XInterface + virtual void SAL_CALL acquire() throw() override { Statement_BASE::acquire(); } + virtual void SAL_CALL release() throw() override { Statement_BASE::release(); } + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & reqType ) override; + +public: // XCloseable + virtual void SAL_CALL close( ) override; + +public: // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( + const OUString& sql ) override; + virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override; + virtual sal_Bool SAL_CALL execute( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + +public: // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // OPropertySetHelper + virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + + void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + // XPropertySet + css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + +public: // XGeneratedResultSet + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + getGeneratedValues( ) override; + +public: // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + +public: // OComponentHelper + virtual void SAL_CALL disposing() override; + +public: // XResultSetMetaDataSupplier (is required by framework (see + // dbaccess/source/core/api/preparedstatement.cxx::getMetaData() ) + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + +private: + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkClosed(); + /// @throws css::sdbc::SQLException + void raiseSQLException( const OUString & sql, const char * errorMsg ); +}; + + +struct CommandData +{ + ConnectionSettings **ppSettings; + sal_Int32 *pLastOidInserted; + sal_Int32 *pMultipleResultUpdateCount; + bool *pMultipleResultAvailable; + OUString *pLastTableInserted; + css::uno::Reference< css::sdbc::XCloseable > *pLastResultset; + OString *pLastQuery; + ::rtl::Reference< comphelper::RefCountedMutex > refMutex; + css::uno::Reference< css::uno::XInterface > owner; + css::uno::Reference< css::sdbcx::XTablesSupplier > tableSupplier; + sal_Int32 concurrency; +}; + +bool executePostgresCommand( const OString & cmd, struct CommandData *data ); +css::uno::Reference< css::sdbc::XResultSet > getGeneratedValuesFromLastInsert( + ConnectionSettings *pConnectionSettings, + const css::uno::Reference< css::sdbc::XConnection > &connection, + sal_Int32 nLastOid, + const OUString & lastTableInserted, + const OString & lastQuery ); + + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_statics.cxx b/connectivity/source/drivers/postgresql/pq_statics.cxx new file mode 100644 index 000000000..a68242e2c --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_statics.cxx @@ -0,0 +1,672 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include "pq_statics.hxx" +#include "pq_updateableresultset.hxx" +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::PropertyAttribute::READONLY; +using com::sun::star::beans::Property; + +namespace pq_sdbc_driver +{ + +namespace { + +struct DefColumnMetaData +{ + const char * columnName; + const char * tableName; + const char * schemaTableName; + const char * typeName; + sal_Int32 type; + sal_Int32 precision; + sal_Int32 scale; + bool isCurrency; + bool isNullable; + bool isAutoIncrement; +}; + +struct BaseTypeDef { const char * typeName; sal_Int32 value; }; + +struct PropertyDef +{ + PropertyDef( const OUString &str, const Type &t ) + : name( str ) , type( t ) {} + OUString name; + css::uno::Type type; +}; + +struct PropertyDefEx : public PropertyDef +{ + PropertyDefEx( const OUString & str, const Type &t , sal_Int32 a ) + : PropertyDef( str, t ) , attribute( a ) + {} + sal_Int32 attribute; +}; + +} + +static cppu::IPropertyArrayHelper * createPropertyArrayHelper( + PropertyDef const *props, int count , sal_Int16 attr ) +{ + Sequence< Property > seq( count ); + for( int i = 0 ; i < count ; i ++ ) + { + seq[i] = Property( props[i].name, i, props[i].type, attr ); + } + return new cppu::OPropertyArrayHelper( seq, true ); +} + +static cppu::IPropertyArrayHelper * createPropertyArrayHelper( + PropertyDefEx const *props, int count ) +{ + Sequence< Property > seq( count ); + for( int i = 0 ; i < count ; i ++ ) + { + seq[i] = Property( props[i].name, i, props[i].type, props[i].attribute ); + } + return new cppu::OPropertyArrayHelper( seq, true ); +} + +Statics & getStatics() +{ + static Statics* p = []() { + static Statics statics ; + statics.SYSTEM_TABLE = "SYSTEM TABLE"; + statics.TABLE = "TABLE"; + statics.VIEW = "VIEW"; + statics.UNKNOWN = "UNKNOWN"; + statics.YES = "YES"; + statics.NO = "NO"; + statics.NO_NULLS = "NO_NULLS"; + statics.NULABLE = "NULABLE"; + statics.NULLABLE_UNKNOWN = "NULLABLE_UNKNOWN"; + + statics.TYPE = "Type"; + statics.TYPE_NAME = "TypeName"; + statics.NAME = "Name"; + statics.SCHEMA_NAME = "SchemaName"; + statics.CATALOG_NAME = "CatalogName"; + statics.DESCRIPTION = "Description"; + statics.PRIVILEGES = "Privileges"; + + statics.DEFAULT_VALUE = "DefaultValue"; + statics.IS_AUTO_INCREMENT = "IsAutoIncrement"; + statics.IS_CURRENCY = "IsCurrency"; + statics.IS_NULLABLE = "IsNullable"; + statics.IS_ROW_VERSISON = "IsRowVersion"; + statics.PRECISION = "Precision"; + statics.SCALE = "Scale"; + + statics.cPERCENT = "%"; + statics.BEGIN = "BEGIN"; + statics.COMMIT = "COMMIT"; + statics.ROLLBACK = "ROLLBACK"; + + statics.KEY = "Key"; + statics.REFERENCED_TABLE = "ReferencedTable"; + statics.UPDATE_RULE = "UpdateRule"; + statics.DELETE_RULE = "DeleteRule"; + statics.PRIVATE_COLUMNS = "PrivateColumns"; + statics.PRIVATE_FOREIGN_COLUMNS = "PrivateForeignColumns"; + + statics.KEY_COLUMN = "KeyColumn"; + statics.RELATED_COLUMN = "RelatedColumn"; + statics.PASSWORD = "Password"; + statics.USER = "User"; + + statics.CURSOR_NAME = "CursorName"; + statics.ESCAPE_PROCESSING = "EscapeProcessing"; + statics.FETCH_DIRECTION = "FetchDirection"; + statics.FETCH_SIZE = "FetchSize"; + statics.IS_BOOKMARKABLE = "IsBookmarkable"; + statics.RESULT_SET_CONCURRENCY = "ResultSetConcurrency"; + statics.RESULT_SET_TYPE = "ResultSetType"; + + statics.COMMAND = "Command"; + statics.CHECK_OPTION = "CheckOption"; + + statics.TRUE = "t"; + statics.FALSE = "f"; + statics.IS_PRIMARY_KEY_INDEX = "IsPrimaryKeyIndex"; + statics.IS_CLUSTERED = "IsClustered"; + statics.IS_UNIQUE = "IsUnique"; + statics.IS_ASCENDING = "IsAscending"; + statics.PRIVATE_COLUMN_INDEXES = "PrivateColumnIndexes"; + statics.HELP_TEXT = "HelpText"; + + statics.CATALOG = "Catalog"; + + Type tString = cppu::UnoType<OUString>::get(); + Type tInt = cppu::UnoType<sal_Int32>::get(); + Type tBool = cppu::UnoType<bool>::get(); + Type tStringSequence = cppu::UnoType<css::uno::Sequence< OUString >>::get(); + + // Table props set + ImplementationStatics &ist = statics.refl.table; + ist.implName = "org.openoffice.comp.pq.sdbcx.Table"; + ist.serviceNames = Sequence< OUString > ( 1 ); + ist.serviceNames[0] = "com.sun.star.sdbcx.Table"; + PropertyDef tableDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DESCRIPTION , tString ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRIVILEGES , tInt ), + PropertyDef( statics.SCHEMA_NAME , tString ), + PropertyDef( statics.TYPE , tString ) + }; + ist.pProps = createPropertyArrayHelper( + tableDef, SAL_N_ELEMENTS(tableDef), READONLY ); + + statics.refl.tableDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.TableDescriptor"; + statics.refl.tableDescriptor.serviceNames = Sequence< OUString > (1); + statics.refl.tableDescriptor.serviceNames[0] = + "com.sun.star.sdbcx.TableDescriptor"; + PropertyDef tableDescDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DESCRIPTION , tString ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRIVILEGES , tInt ), + PropertyDef( statics.SCHEMA_NAME , tString ) + }; + statics.refl.tableDescriptor.pProps = createPropertyArrayHelper( + tableDescDef, SAL_N_ELEMENTS(tableDescDef), 0 ); + + // Column props set + statics.refl.column.implName = "org.openoffice.comp.pq.sdbcx.Column"; + statics.refl.column.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.column.serviceNames[0] = "com.sun.star.sdbcx.Column"; + PropertyDefEx columnDef[] = + { + PropertyDefEx( statics.CATALOG_NAME , tString, READONLY ), + PropertyDefEx( statics.DEFAULT_VALUE, tString, READONLY ), + PropertyDefEx( statics.DESCRIPTION , tString, READONLY ), +// PropertyDefEx( statics.HELP_TEXT , tString, BOUND ), + PropertyDefEx( statics.IS_AUTO_INCREMENT, tBool, READONLY ), + PropertyDefEx( statics.IS_CURRENCY, tBool, READONLY ), + PropertyDefEx( statics.IS_NULLABLE, tInt, READONLY ), + PropertyDefEx( statics.IS_ROW_VERSISON, tBool,READONLY ), + PropertyDefEx( statics.NAME , tString,READONLY ), + PropertyDefEx( statics.PRECISION , tInt, READONLY ), + PropertyDefEx( statics.SCALE , tInt ,READONLY), + PropertyDefEx( statics.TYPE , tInt ,READONLY), + PropertyDefEx( statics.TYPE_NAME , tString ,READONLY) + }; + statics.refl.column.pProps = createPropertyArrayHelper( + columnDef, SAL_N_ELEMENTS(columnDef) ); + + statics.refl.columnDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.ColumnDescriptor"; + statics.refl.columnDescriptor.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.columnDescriptor.serviceNames[0] = + "com.sun.star.sdbcx.ColumnDescriptor"; + PropertyDef columnDescDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DEFAULT_VALUE, tString ), + PropertyDef( statics.DESCRIPTION , tString ), +// PropertyDef( statics.HELP_TEXT , tString ), + PropertyDef( statics.IS_AUTO_INCREMENT, tBool ), + PropertyDef( statics.IS_CURRENCY, tBool ), + PropertyDef( statics.IS_NULLABLE, tInt ), + PropertyDef( statics.IS_ROW_VERSISON, tBool ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRECISION , tInt ), + PropertyDef( statics.SCALE , tInt ), + PropertyDef( statics.TYPE , tInt ), + PropertyDef( statics.TYPE_NAME , tString ) + }; + + statics.refl.columnDescriptor.pProps = createPropertyArrayHelper( + columnDescDef, SAL_N_ELEMENTS(columnDescDef), 0 ); + + // Key properties + statics.refl.key.implName = "org.openoffice.comp.pq.sdbcx.Key"; + statics.refl.key.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.key.serviceNames[0] = "com.sun.star.sdbcx.Key"; + PropertyDef keyDef[] = + { + PropertyDef( statics.DELETE_RULE, tInt ), + PropertyDef( statics.NAME, tString ), + PropertyDef( statics.PRIVATE_COLUMNS, tStringSequence ), + PropertyDef( statics.PRIVATE_FOREIGN_COLUMNS, tStringSequence ), + PropertyDef( statics.REFERENCED_TABLE, tString ), + PropertyDef( statics.TYPE, tInt ), + PropertyDef( statics.UPDATE_RULE, tInt ) + }; + statics.refl.key.pProps = createPropertyArrayHelper( + keyDef, SAL_N_ELEMENTS(keyDef), READONLY ); + + + // Key properties + statics.refl.keyDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.KeyDescriptor"; + statics.refl.keyDescriptor.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.keyDescriptor.serviceNames[0] = + "com.sun.star.sdbcx.KeyDescriptor"; + PropertyDef keyDescDef[] = + { + PropertyDef( statics.DELETE_RULE, tInt ), + PropertyDef( statics.NAME, tString ), + PropertyDef( statics.REFERENCED_TABLE, tString ), + PropertyDef( statics.TYPE, tInt ), + PropertyDef( statics.UPDATE_RULE, tInt ) + }; + statics.refl.keyDescriptor.pProps = createPropertyArrayHelper( + keyDescDef, SAL_N_ELEMENTS(keyDescDef), 0 ); + + + // KeyColumn props set + statics.refl.keycolumn.implName = "org.openoffice.comp.pq.sdbcx.KeyColumn"; + statics.refl.keycolumn.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.keycolumn.serviceNames[0] = "com.sun.star.sdbcx.KeyColumn"; + PropertyDef keycolumnDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DEFAULT_VALUE, tString ), + PropertyDef( statics.DESCRIPTION , tString ), + PropertyDef( statics.IS_AUTO_INCREMENT, tBool ), + PropertyDef( statics.IS_CURRENCY, tBool ), + PropertyDef( statics.IS_NULLABLE, tInt ), + PropertyDef( statics.IS_ROW_VERSISON, tBool ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRECISION , tInt ), + PropertyDef( statics.RELATED_COLUMN, tString ), + PropertyDef( statics.SCALE , tInt ), + PropertyDef( statics.TYPE , tInt ), + PropertyDef( statics.TYPE_NAME , tString ) + }; + statics.refl.keycolumn.pProps = createPropertyArrayHelper( + keycolumnDef, SAL_N_ELEMENTS(keycolumnDef), READONLY ); + + // KeyColumn props set + statics.refl.keycolumnDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.KeyColumnDescriptor"; + statics.refl.keycolumnDescriptor.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.keycolumnDescriptor.serviceNames[0] = + "com.sun.star.sdbcx.KeyColumnDescriptor"; + PropertyDef keycolumnDescDef[] = + { + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.RELATED_COLUMN, tString ) + }; + statics.refl.keycolumnDescriptor.pProps = createPropertyArrayHelper( + keycolumnDescDef, SAL_N_ELEMENTS(keycolumnDescDef), 0 ); + + // view props set + statics.refl.view.implName = "org.openoffice.comp.pq.sdbcx.View"; + statics.refl.view.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.view.serviceNames[0] = "com.sun.star.sdbcx.View"; + PropertyDef viewDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.CHECK_OPTION , tInt ), + PropertyDef( statics.COMMAND , tString ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.SCHEMA_NAME , tString ) + }; + statics.refl.view.pProps = createPropertyArrayHelper( + viewDef, SAL_N_ELEMENTS(viewDef), READONLY ); + + // view props set + statics.refl.viewDescriptor.implName = "org.openoffice.comp.pq.sdbcx.ViewDescriptor"; + statics.refl.viewDescriptor.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.viewDescriptor.serviceNames[0] = "com.sun.star.sdbcx.ViewDescriptor"; + statics.refl.viewDescriptor.pProps = createPropertyArrayHelper( + viewDef, SAL_N_ELEMENTS(viewDef), 0 ); // reuse view, as it is identical + // user props set + statics.refl.user.implName = "org.openoffice.comp.pq.sdbcx.User"; + statics.refl.user.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.user.serviceNames[0] = "com.sun.star.sdbcx.User"; + PropertyDef userDefRO[] = + { + PropertyDef( statics.NAME , tString ) + }; + statics.refl.user.pProps = createPropertyArrayHelper( + userDefRO, SAL_N_ELEMENTS(userDefRO), READONLY ); + + // user props set + statics.refl.userDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.UserDescriptor"; + statics.refl.userDescriptor.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.userDescriptor.serviceNames[0] = + "com.sun.star.sdbcx.UserDescriptor"; + PropertyDef userDefWR[] = + { + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PASSWORD , tString ) + }; + statics.refl.userDescriptor.pProps = createPropertyArrayHelper( + userDefWR, SAL_N_ELEMENTS(userDefWR), 0 ); + + // index props set + statics.refl.index.implName = "org.openoffice.comp.pq.sdbcx.Index"; + statics.refl.index.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.index.serviceNames[0] = "com.sun.star.sdbcx.Index"; + PropertyDef indexDef[] = + { + PropertyDef( statics.CATALOG , tString ), + PropertyDef( statics.IS_CLUSTERED, tBool ), + PropertyDef( statics.IS_PRIMARY_KEY_INDEX, tBool ), + PropertyDef( statics.IS_UNIQUE, tBool ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRIVATE_COLUMN_INDEXES, tStringSequence ) + }; + statics.refl.index.pProps = createPropertyArrayHelper( + indexDef, SAL_N_ELEMENTS(indexDef), READONLY ); + + // index props set + statics.refl.indexDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.IndexDescriptor"; + statics.refl.indexDescriptor.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.indexDescriptor.serviceNames[0] = + "com.sun.star.sdbcx.IndexDescriptor"; + statics.refl.indexDescriptor.pProps = createPropertyArrayHelper( + indexDef, SAL_N_ELEMENTS(indexDef), 0 ); + + // indexColumn props set + statics.refl.indexColumn.implName = "org.openoffice.comp.pq.sdbcx.IndexColumn"; + statics.refl.indexColumn.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.indexColumn.serviceNames[0] = "com.sun.star.sdbcx.IndexColumn"; + PropertyDef indexColumnDef[] = + { + PropertyDef( statics.CATALOG_NAME , tString ), + PropertyDef( statics.DEFAULT_VALUE, tString ), + PropertyDef( statics.DESCRIPTION , tString ), + PropertyDef( statics.IS_ASCENDING, tBool ), + PropertyDef( statics.IS_AUTO_INCREMENT, tBool ), + PropertyDef( statics.IS_CURRENCY, tBool ), + PropertyDef( statics.IS_NULLABLE, tInt ), + PropertyDef( statics.IS_ROW_VERSISON, tBool ), + PropertyDef( statics.NAME , tString ), + PropertyDef( statics.PRECISION , tInt ), + PropertyDef( statics.SCALE , tInt ), + PropertyDef( statics.TYPE , tInt ), + PropertyDef( statics.TYPE_NAME , tString ) + }; + statics.refl.indexColumn.pProps = createPropertyArrayHelper( + indexColumnDef, SAL_N_ELEMENTS(indexColumnDef), READONLY ); + + // indexColumn props set + statics.refl.indexColumnDescriptor.implName = + "org.openoffice.comp.pq.sdbcx.IndexColumnDescriptor"; + statics.refl.indexColumnDescriptor.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.indexColumnDescriptor.serviceNames[0] = + "com.sun.star.sdbcx.IndexColumnDescriptor"; + PropertyDef indexColumnDescDef[] = + { + PropertyDef( statics.IS_ASCENDING, tBool ), + PropertyDef( statics.NAME , tString ) + }; + statics.refl.indexColumnDescriptor.pProps = createPropertyArrayHelper( + indexColumnDescDef, SAL_N_ELEMENTS(indexColumnDescDef), 0 ); + + // resultset + statics.refl.resultSet.implName = "org.openoffice.comp.pq.ResultSet"; + statics.refl.resultSet.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.resultSet.serviceNames[0] = "com.sun.star.sdbc.ResultSet"; + statics.refl.resultSet.types = UpdateableResultSet::getStaticTypes( false /* updateable */ ); + PropertyDef resultSet[] = + { + PropertyDef( statics.CURSOR_NAME , tString ), + PropertyDef( statics.ESCAPE_PROCESSING , tBool ), + PropertyDef( statics.FETCH_DIRECTION , tInt ), + PropertyDef( statics.FETCH_SIZE , tInt ), + PropertyDef( statics.IS_BOOKMARKABLE , tBool ), + PropertyDef( statics.RESULT_SET_CONCURRENCY , tInt ), + PropertyDef( statics.RESULT_SET_TYPE , tInt ) + }; + statics.refl.resultSet.pProps = createPropertyArrayHelper( + resultSet, SAL_N_ELEMENTS(resultSet), 0 ); + + // updateableResultset + statics.refl.updateableResultSet.implName = "org.openoffice.comp.pq.UpdateableResultSet"; + statics.refl.updateableResultSet.serviceNames = Sequence< OUString > ( 1 ); + statics.refl.updateableResultSet.serviceNames[0] = "com.sun.star.sdbc.ResultSet"; + statics.refl.updateableResultSet.types = UpdateableResultSet::getStaticTypes( true /* updateable */ ); + statics.refl.updateableResultSet.pProps = createPropertyArrayHelper( + resultSet, SAL_N_ELEMENTS(resultSet), 0 ); + + // databasemetadata + statics.tablesRowNames = std::vector< OUString > ( 5 ); + statics.tablesRowNames[TABLE_INDEX_CATALOG] = "TABLE_CAT"; + statics.tablesRowNames[TABLE_INDEX_SCHEMA] = "TABLE_SCHEM"; + statics.tablesRowNames[TABLE_INDEX_NAME] = "TABLE_NAME"; + statics.tablesRowNames[TABLE_INDEX_TYPE] = "TABLE_TYPE"; + statics.tablesRowNames[TABLE_INDEX_REMARKS] = "REMARKS"; + + statics.primaryKeyNames = std::vector< OUString > ( 6 ); + statics.primaryKeyNames[0] = "TABLE_CAT"; + statics.primaryKeyNames[1] = "TABLE_SCHEM"; + statics.primaryKeyNames[2] = "TABLE_NAME"; + statics.primaryKeyNames[3] = "COLUMN_NAME"; + statics.primaryKeyNames[4] = "KEY_SEQ"; + statics.primaryKeyNames[5] = "PK_NAME"; + + statics.SELECT = "SELECT"; + statics.UPDATE = "UPDATE"; + statics.INSERT = "INSERT"; + statics.DELETE = "DELETE"; + statics.RULE = "RULE"; + statics.REFERENCES = "REFERENCES"; + statics.TRIGGER = "TRIGGER"; + statics.EXECUTE = "EXECUTE"; + statics.USAGE = "USAGE"; + statics.CREATE = "CREATE"; + statics.TEMPORARY = "TEMPORARY"; + statics.INDEX = "Index"; + statics.INDEX_COLUMN = "IndexColumn"; + + statics.schemaNames = std::vector< OUString > ( 1 ); + statics.schemaNames[0] = "TABLE_SCHEM"; + + statics.tableTypeData = std::vector< std::vector< Any > >( 2 ); + + statics.tableTypeData[0] = std::vector< Any > ( 1 ); + statics.tableTypeData[0][0] <<= statics.TABLE; + +// statics.tableTypeData[2] = Sequence< Any > ( 1 ); +// statics.tableTypeData[2][0] <<= statics.VIEW; + + statics.tableTypeData[1] = std::vector< Any > ( 1 ); + statics.tableTypeData[1][0] <<= statics.SYSTEM_TABLE; + + statics.tableTypeNames = std::vector< OUString > ( 1 ); + statics.tableTypeNames[0] = "TABLE_TYPE"; + + statics.columnRowNames = + { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", + "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", + "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", "REMARKS", + "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", "IS_NULLABLE" + }; + + statics.typeinfoColumnNames = + { + "TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", + "LITERAL_SUFFIX", "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", + "SEARCHABLE", "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", + "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", + "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", + "NUM_PREC_RADIX" + }; + + statics.indexinfoColumnNames = + { + "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", + "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME", + "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", + "ASC_OR_DESC", "CARDINALITY", "PAGES", "FILTER_CONDITION" + }; + + statics.resultSetArrayColumnNames = { "INDEX" , "VALUE" }; + + // LEM TODO see if a refresh is needed; obtain automatically from pg_catalog.pg_type? + BaseTypeDef baseTypeDefs[] = + { + { "bool" , css::sdbc::DataType::BOOLEAN }, + { "bytea", css::sdbc::DataType::VARBINARY }, + { "char" , css::sdbc::DataType::CHAR }, + + { "int8" , css::sdbc::DataType::BIGINT }, + { "serial8" , css::sdbc::DataType::BIGINT }, + + + { "int2" , css::sdbc::DataType::SMALLINT }, + + { "int4" , css::sdbc::DataType::INTEGER }, +// { "regproc" , css::sdbc::DataType::INTEGER }, +// { "oid" , css::sdbc::DataType::INTEGER }, +// { "xid" , css::sdbc::DataType::INTEGER }, +// { "cid" , css::sdbc::DataType::INTEGER }, +// { "serial", css::sdbc::DataType::INTEGER }, +// { "serial4", css::sdbc::DataType::INTEGER }, + + { "text", css::sdbc::DataType::LONGVARCHAR }, + { "bpchar", css::sdbc::DataType::CHAR }, + { "varchar", css::sdbc::DataType::VARCHAR }, + + { "float4", css::sdbc::DataType::REAL }, + { "float8", css::sdbc::DataType::DOUBLE }, + + { "numeric", css::sdbc::DataType::NUMERIC }, + { "decimal", css::sdbc::DataType::DECIMAL }, + + { "date", css::sdbc::DataType::DATE }, + { "time", css::sdbc::DataType::TIME }, + { "timestamp", css::sdbc::DataType::TIMESTAMP }, + +// { "_bool" , css::sdbc::DataType::ARRAY }, +// { "_bytea", css::sdbc::DataType::ARRAY }, +// { "_char" , css::sdbc::DataType::ARRAY }, + +// { "_int8" , css::sdbc::DataType::ARRAY }, +// { "_serial8" , css::sdbc::DataType::ARRAY }, + + +// { "_int2" , css::sdbc::DataType::ARRAY }, + +// { "_int4" , css::sdbc::DataType::ARRAY }, +// { "_regproc" , css::sdbc::DataType::ARRAY }, +// { "_oid" , css::sdbc::DataType::ARRAY }, +// { "_xid" , css::sdbc::DataType::ARRAY }, +// { "_cid" , css::sdbc::DataType::ARRAY }, + +// { "_text", css::sdbc::DataType::ARRAY }, +// { "_bpchar", css::sdbc::DataType::ARRAY }, +// { "_varchar", css::sdbc::DataType::ARRAY }, + +// { "_float4", css::sdbc::DataType::ARRAY }, +// { "_float8", css::sdbc::DataType::ARRAY }, + +// { "_numeric", css::sdbc::DataType::ARRAY }, +// { "_decimal", css::sdbc::DataType::ARRAY }, + +// { "_date", css::sdbc::DataType::ARRAY }, // switch to date later +// { "_time", css::sdbc::DataType::ARRAY }, // switch to time later + + { nullptr, 0 } + }; + int i; + for( i = 0 ; baseTypeDefs[i].typeName ; i ++ ) + { + statics.baseTypeMap[ + OUString::createFromAscii( baseTypeDefs[i].typeName) ] = + baseTypeDefs[i].value; + } + + // This is the metadata for the columns of the recordset returned + // by css::sdbc::XDatabaseMetaData::getTypeInfo(), + // that is what is returned by getTypeInfo().getMetaData() + DefColumnMetaData defTypeInfoMetaData[] = + { + { "TYPE_NAME", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 0 + { "DATA_TYPE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 1 + { "PRECISION", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 2 + { "LITERAL_PREFIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 3 + { "LITERAL_SUFFIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 4 + { "CREATE_PARAMS", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 5 + { "NULLABLE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 6 + { "CASE_SENSITIVE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 7 + { "SEARCHABLE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 8 + { "UNSIGNED_ATTRIBUTE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 9 + { "FIXED_PREC_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 10 + { "AUTO_INCREMENT", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::BOOLEAN, 0,50,false,false,false }, // 11 + { "LOCAL_TYPE_NAME", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::VARCHAR, 0,50,false,false,false }, // 12 + { "MINIMUM_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false}, // 13 + { "MAXIMUM_SCALE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::SMALLINT, 0,50,false,false,false }, // 14 + { "SQL_DATA_TYPE", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 15 + { "SQL_DATETIME_SUB", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false}, // 16 + { "NUM_PREC_RADIX", "TYPEINFO", "pg_catalog", "", css::sdbc::DataType::INTEGER, 0,50,false,false,false }, // 17 + {nullptr,nullptr,nullptr,nullptr,0,0,0,false,false,false} + }; + + for( i = 0 ; defTypeInfoMetaData[i].columnName ; i++ ) + { + statics.typeInfoMetaData.push_back( + ColumnMetaData( + OUString::createFromAscii( defTypeInfoMetaData[i].columnName ), + OUString::createFromAscii( defTypeInfoMetaData[i].tableName ), + OUString::createFromAscii( defTypeInfoMetaData[i].schemaTableName ), + OUString::createFromAscii( defTypeInfoMetaData[i].typeName ), + defTypeInfoMetaData[i].type, + defTypeInfoMetaData[i].precision, + defTypeInfoMetaData[i].scale, + defTypeInfoMetaData[i].isCurrency, + defTypeInfoMetaData[i].isNullable, + defTypeInfoMetaData[i].isAutoIncrement ) ); + } + + return &statics; + }(); + return *p; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_statics.hxx b/connectivity/source/drivers/postgresql/pq_statics.hxx new file mode 100644 index 000000000..78051cd69 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_statics.hxx @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_STATICS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_STATICS_HXX + +#include <unordered_map> +#include <vector> + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <cppuhelper/propshlp.hxx> + +namespace pq_sdbc_driver +{ + +struct ColumnMetaData +{ + ColumnMetaData( + const OUString &_columnName, + const OUString &_tableName, + const OUString &_schemaTableName, + const OUString &_typeName, + sal_Int32 _type, + sal_Int32 _precision, + sal_Int32 _scale, + bool _isCurrency, + bool _isNullable, + bool _isAutoIncrement ) : + columnName( _columnName ), + tableName( _tableName ), + schemaTableName( _schemaTableName ), + typeName( _typeName ), + type( _type ), + precision( _precision ), + scale( _scale ), + isCurrency( _isCurrency ), + isNullable( _isNullable ), + isAutoIncrement( _isAutoIncrement ) + {} + + OUString columnName; + OUString tableName; + OUString schemaTableName; + OUString typeName; + sal_Int32 type; + sal_Int32 precision; + sal_Int32 scale; + bool isCurrency; + bool isNullable; + bool isAutoIncrement; +}; + +typedef std::vector< ColumnMetaData > ColumnMetaDataVector; + +typedef std::unordered_map +< + OUString, + sal_Int32 +> BaseTypeMap; + +struct ImplementationStatics +{ + ImplementationStatics() : + pProps(nullptr) + {} + + OUString implName; + css::uno::Sequence< OUString > serviceNames; + cppu::IPropertyArrayHelper *pProps; + css::uno::Sequence< css::uno::Type > types; +}; + +struct ReflectionImplementations +{ + struct ImplementationStatics table; + struct ImplementationStatics tableDescriptor; + struct ImplementationStatics column; + struct ImplementationStatics columnDescriptor; + struct ImplementationStatics key; + struct ImplementationStatics keyDescriptor; + struct ImplementationStatics keycolumn; + struct ImplementationStatics keycolumnDescriptor; + struct ImplementationStatics user; + struct ImplementationStatics userDescriptor; + struct ImplementationStatics view; + struct ImplementationStatics viewDescriptor; + struct ImplementationStatics index; + struct ImplementationStatics indexDescriptor; + struct ImplementationStatics indexColumn; + struct ImplementationStatics indexColumnDescriptor; + + struct ImplementationStatics updateableResultSet; + struct ImplementationStatics resultSet; +}; + +static const sal_Int32 TABLE_INDEX_CATALOG = 0; +static const sal_Int32 TABLE_INDEX_SCHEMA = 1; +static const sal_Int32 TABLE_INDEX_NAME = 2; +static const sal_Int32 TABLE_INDEX_TYPE = 3; +static const sal_Int32 TABLE_INDEX_REMARKS = 4; + +struct Statics +{ + OUString SYSTEM_TABLE; + OUString TABLE; + OUString VIEW; + OUString UNKNOWN; + OUString YES; + OUString NO; + OUString NO_NULLS; + OUString NULABLE; + OUString NULLABLE_UNKNOWN; + OUString SELECT; + OUString UPDATE; + OUString INSERT; + OUString DELETE; + OUString RULE; + OUString REFERENCES; + OUString TRIGGER; + OUString EXECUTE; + OUString USAGE; + OUString CREATE; + OUString TEMPORARY; + OUString INDEX; + OUString INDEX_COLUMN; + + OUString NAME; + OUString SCHEMA_NAME; + OUString CATALOG_NAME; + OUString DESCRIPTION; + OUString TYPE; + OUString TYPE_NAME; + OUString PRIVILEGES; + + OUString DEFAULT_VALUE; + OUString IS_AUTO_INCREMENT; + OUString IS_CURRENCY; + OUString IS_NULLABLE; + OUString IS_ROW_VERSISON; + OUString PRECISION; + OUString SCALE; + + OUString cPERCENT; + + OUString BEGIN; + OUString ROLLBACK; + OUString COMMIT; + + OUString KEY; + OUString REFERENCED_TABLE; + OUString UPDATE_RULE; + OUString DELETE_RULE; + OUString PRIVATE_COLUMNS; + OUString PRIVATE_FOREIGN_COLUMNS; + + OUString KEY_COLUMN; + OUString RELATED_COLUMN; + + OUString PASSWORD; + OUString USER; + + OUString CURSOR_NAME; + OUString ESCAPE_PROCESSING; + OUString FETCH_DIRECTION; + OUString FETCH_SIZE; + OUString IS_BOOKMARKABLE; + OUString RESULT_SET_CONCURRENCY; + OUString RESULT_SET_TYPE; + + OUString COMMAND; + OUString CHECK_OPTION; + + OUString TRUE; + OUString FALSE; + + OUString IS_PRIMARY_KEY_INDEX; + OUString IS_CLUSTERED; + OUString IS_UNIQUE; + OUString PRIVATE_COLUMN_INDEXES; + OUString HELP_TEXT; + + OUString CATALOG; + OUString IS_ASCENDING; + ReflectionImplementations refl; + + std::vector< OUString > tablesRowNames; + std::vector< OUString > columnRowNames; + std::vector< OUString > primaryKeyNames; + std::vector< OUString > schemaNames; + std::vector< OUString > tableTypeNames; + std::vector< OUString > typeinfoColumnNames; + std::vector< OUString > indexinfoColumnNames; + std::vector< OUString > resultSetArrayColumnNames; + std::vector< std::vector< css::uno::Any > > tableTypeData; + + ColumnMetaDataVector typeInfoMetaData; + BaseTypeMap baseTypeMap; + Statics(){} +private: + Statics( const Statics & ) = delete; + Statics & operator = ( const Statics & ) = delete; +}; + +Statics & getStatics(); + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_tools.cxx b/connectivity/source/drivers/postgresql/pq_tools.cxx new file mode 100644 index 000000000..bece8a806 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_tools.cxx @@ -0,0 +1,1247 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/config.h> + +#include <o3tl/any.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> + +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +#include <libpq-fe.h> +#include <string.h> + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::lang::XComponent; + +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XConnection; +using com::sun::star::sdbc::XPreparedStatement; +using com::sun::star::sdbc::XParameters; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XRow; + +using com::sun::star::sdbcx::XColumnsSupplier; + +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; + +using com::sun::star::container::XEnumeration; +using com::sun::star::container::XEnumerationAccess; + +namespace pq_sdbc_driver +{ + +OUString concatQualified( const OUString & a, const OUString &b) +{ + return a + "." + b; +} + +static OString iOUStringToOString( const OUString& str, ConnectionSettings const *settings) { + OSL_ENSURE(settings, "pgsql-sdbc: OUStringToOString got NULL settings"); + return OUStringToOString( str, ConnectionSettings::encoding ); +} + +OString OUStringToOString( const OUString& str, ConnectionSettings const *settings) { + return iOUStringToOString( str, settings ); +} + +void bufferEscapeConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings ) +{ + + OString y = iOUStringToOString( value, settings ); + OStringBuffer strbuf( y.getLength() * 2 + 2 ); + int error; + int len = PQescapeStringConn(settings->pConnection, const_cast<char*>(strbuf.getStr()), y.getStr() , y.getLength(), &error ); + if ( error ) + { + char *errstr = PQerrorMessage(settings->pConnection); + // As of PostgreSQL 9.1, the only possible errors "involve invalid multibyte encoding" + // According to https://www2.opengroup.org/ogsys/jsp/publications/PublicationDetails.jsp?publicationid=11216 + // (X/Open SQL CLI, March 1995, ISBN: 1-85912-081-4, X/Open Document Number: C451) + // 22018 is for "Invalid character value" and seems to be the best match. + // We have no good XInterface Reference to pass here, so just give NULL + throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding), + nullptr, + "22018", + -1, + Any()); + } + strbuf.setLength( len ); + // Previously here RTL_TEXTENCODING_ASCII_US; as we set the PostgreSQL client_encoding to UTF8, + // we get UTF8 here, too. I'm not sure why it worked well before... + buf.append( OStringToOUString( strbuf.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ) ); +} + +static void ibufferQuoteConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings ) +{ + buf.append( "'" ); + bufferEscapeConstant( buf, value, settings ); + buf.append( "'" ); +} + +void bufferQuoteConstant( OUStringBuffer & buf, const OUString & value, ConnectionSettings *settings ) +{ + return ibufferQuoteConstant( buf, value, settings ); +} + +void bufferQuoteAnyConstant( OUStringBuffer & buf, const Any &val, ConnectionSettings *settings ) +{ + if( val.hasValue() ) + { + OUString str; + val >>= str; + bufferQuoteConstant( buf, str, settings ); + } + else + buf.append( "NULL" ); +} + +static void ibufferQuoteIdentifier( OUStringBuffer & buf, const OUString &toQuote, ConnectionSettings *settings ) +{ + OSL_ENSURE(settings, "pgsql-sdbc: bufferQuoteIdentifier got NULL settings"); + + OString y = iOUStringToOString( toQuote, settings ); + char *cstr = PQescapeIdentifier(settings->pConnection, y.getStr(), y.getLength()); + if ( cstr == nullptr ) + { + char *errstr = PQerrorMessage(settings->pConnection); + // Implementation-defined SQLACCESS error + throw SQLException(OUString(errstr, strlen(errstr), ConnectionSettings::encoding), + nullptr, + "22018", + -1, + Any()); + } + buf.append( OStringToOUString( cstr, RTL_TEXTENCODING_UTF8 ) ); + PQfreemem( cstr ); +} + +void bufferQuoteIdentifier( OUStringBuffer & buf, const OUString &toQuote, ConnectionSettings *settings ) +{ + return ibufferQuoteIdentifier(buf, toQuote, settings); +} + + +void bufferQuoteQualifiedIdentifier( + OUStringBuffer & buf, const OUString &schema, const OUString &table, ConnectionSettings *settings ) +{ + ibufferQuoteIdentifier(buf, schema, settings); + buf.append( "." ); + ibufferQuoteIdentifier(buf, table, settings); +} + +void bufferQuoteQualifiedIdentifier( + OUStringBuffer & buf, + const OUString &schema, + const OUString &table, + const OUString &col, + ConnectionSettings *settings) +{ + ibufferQuoteIdentifier(buf, schema, settings); + buf.append( "." ); + ibufferQuoteIdentifier(buf, table, settings); + buf.append( "." ); + ibufferQuoteIdentifier(buf, col, settings); +} + + +OUString extractStringProperty( + const Reference< XPropertySet > & descriptor, const OUString &name ) +{ + OUString value; + descriptor->getPropertyValue( name ) >>= value; + return value; +} + +bool extractBoolProperty( + const Reference< XPropertySet > & descriptor, const OUString &name ) +{ + bool value = false; + descriptor->getPropertyValue( name ) >>= value; + return value; +} + +sal_Int32 extractIntProperty( + const Reference< XPropertySet > & descriptor, const OUString &name ) +{ + sal_Int32 ret = 0; + descriptor->getPropertyValue( name ) >>= ret; + return ret; +} + +void disposeObject( const css::uno::Reference< css::uno::XInterface > & r ) +{ + Reference< XComponent > comp( r, UNO_QUERY ); + if( comp.is() ) + comp->dispose(); +} + +void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r ) +{ + try + { + disposeObject( r ); + } + catch( SQLException & ) + { + // ignore this + } + +} + +Reference< XConnection > extractConnectionFromStatement( const Reference< XInterface > & stmt ) +{ + Reference< XConnection > ret; + + Reference< css::sdbc::XStatement > owner( stmt, UNO_QUERY ); + if( owner.is() ) + ret = owner->getConnection(); + else + { + Reference< css::sdbc::XPreparedStatement > myowner( stmt, UNO_QUERY ); + if( myowner.is() ) + ret = myowner->getConnection(); + if( ! ret.is() ) + throw SQLException( + "PQSDBC: Couldn't retrieve connection from statement", + Reference< XInterface > () , OUString(), 0 , css::uno::Any() ); + } + + return ret; + +} + +DisposeGuard::DisposeGuard( const Reference< XInterface > & r ) + : d( r ) +{} + +DisposeGuard::~DisposeGuard() +{ + disposeNoThrow( d ); +} + +TransactionGuard::TransactionGuard( const Reference< XStatement > &stmt ) + : m_stmt( stmt ), + m_commited( false ) +{ + m_stmt->executeUpdate( getStatics().BEGIN ); +} + +void TransactionGuard::commit() +{ + m_stmt->executeUpdate( getStatics().COMMIT ); + m_commited = true; +} + +void TransactionGuard::executeUpdate( const OUString & sql ) +{ + m_stmt->executeUpdate( sql ); +} + +TransactionGuard::~TransactionGuard() +{ + try + { + if( ! m_commited ) + m_stmt->executeUpdate( getStatics().ROLLBACK ); + } + catch( css::uno::Exception & ) + { + // ignore, we are within a dtor + } + + disposeNoThrow( m_stmt ); +} + + +bool isWhitespace( sal_Unicode c ) +{ + return ' ' == c || 9 == c || 10 == c || 13 == c; +} + +OUString extractTableFromInsert( const OUString & sql ) +{ + OUString ret; + int i = 0; + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + + if( sql.matchIgnoreAsciiCase("insert", i) ) + { + i += 6; + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + if( sql.matchIgnoreAsciiCase("into", i) ) + { + i +=4; + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + int start = i; + bool quote = (sql[i] == '"'); + for( i++ ; i < sql.getLength() ; i ++ ) + { + if( quote && sql[i] == '"' ) + { + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + if( '.' == sql[i] ) + { + while (i < sql.getLength() && isWhitespace(sql[i])) { i++; } + if( '"' == sql[i] ) + { + // the second part of the table name does not use quotes + // parse on + quote = false; + } + } + else + { + // end quoted name, ok + break; + } + } + else + { + if( isWhitespace( sql[i] ) ) + { + // found the end of an unquoted name + break; + } + } + } + ret = sql.copy(start, i - start ).trim(); +// printf( "pq_statement: parsed table name %s from insert\n" , +// OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US).getStr() ); + } + } + return ret; +} + + +static bool isOperator( char c ) +{ + bool ret; + switch(c) + { + case '+': + case '-': + case '*': + case '/': + case '<': + case '>': + case '=': + case '~': + case '!': + case '@': + case '#': + case '%': + case '^': + case '&': + case '|': + case '`': + case '?': + case '$': + ret = true; + break; + default: + ret = false; + } + return ret; +} + +void splitSQL( const OString & sql, std::vector< OString > &vec ) +{ + int length = sql.getLength(); + + int i = 0; + bool singleQuote = false; + bool doubleQuote = false; + int start = 0; + for( ; i < length ; i ++ ) + { + char c = sql[i]; + if( doubleQuote ) + { + if( '"' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i-start+1 ) ); + start = i + 1; + doubleQuote = false; + } + } + else if( singleQuote ) + { + if( '\'' == c && (i+1) < length && '\'' == sql[i+1] ) + { + // two subsequent single quotes within a quoted string + // mean a single quote within the string + i ++; + } + else if( '\'' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i - start +1 ) ); + start = i + 1; // leave single quotes ! + singleQuote = false; + } + } + else + { + if( '"' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + doubleQuote = true; + start = i; + } + else if( '\'' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + singleQuote = true; + start = i; + } + } + } + if( start < i ) + vec.push_back( OString( &sql.getStr()[start] , i - start ) ); + +// for( i = 0 ; i < vec.size() ; i ++ ) +// printf( "%s!" , vec[i].getStr() ); +// printf( "\n" ); + +} + +void tokenizeSQL( const OString & sql, std::vector< OString > &vec ) +{ + int length = sql.getLength(); + + int i = 0; + bool singleQuote = false; + bool doubleQuote = false; + int start = 0; + for( ; i < length ; i ++ ) + { + char c = sql[i]; + if( doubleQuote ) + { + if( '"' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i-start ) ); + start = i + 1; + doubleQuote = false; + } + } + else if( singleQuote ) + { + if( '\'' == c ) + { + vec.push_back( OString( &sql.getStr()[start], i - start +1 ) ); + start = i + 1; // leave single quotes ! + singleQuote = false; + } + } + else + { + if( '"' == c ) + { + doubleQuote = true; + start = i +1; // skip double quotes ! + } + else if( '\'' == c ) + { + singleQuote = true; + start = i; // leave single quotes + } + else if( isWhitespace( c ) ) + { + if( i == start ) + start ++; // skip additional whitespace + else + { + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + start = i +1; + } + } + else if( ',' == c || isOperator( c ) || '(' == c || ')' == c ) + { + if( i - start ) + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + vec.push_back( OString( &sql.getStr()[i], 1 ) ); + start = i + 1; + } + else if( '.' == c ) + { + if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) || + ( i == start && i > 1 && isWhitespace( sql[i-1] ) ) ) + { + // ignore, is a literal + } + else + { + if( i - start ) + vec.push_back( OString( &sql.getStr()[start], i - start ) ); + vec.push_back( OString( "." ) ); + start = i + 1; + } + } + } + } + if( start < i ) + vec.push_back( OString( &sql.getStr()[start] , i - start ) ); + +// for( i = 0 ; i < vec.size() ; i ++ ) +// printf( "%s!" , vec[i].getStr() ); +// printf( "\n" ); +} + + +void splitConcatenatedIdentifier( const OUString & source, OUString *first, OUString *second) +{ + std::vector< OString > vec; + tokenizeSQL( OUStringToOString( source, RTL_TEXTENCODING_UTF8 ), vec ); + switch (vec.size()) + { + case 1: + first->clear(); + *second = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 ); + break; + case 3: + *first = OStringToOUString( vec[0], RTL_TEXTENCODING_UTF8 ); + *second = OStringToOUString( vec[2], RTL_TEXTENCODING_UTF8 ); + break; + default: + SAL_WARN("connectivity.postgresql", + "pq_tools::splitConcatenatedIdentifier unexpected number of tokens in identifier: " + << vec.size()); + } +} + +OUString array2String( const css::uno::Sequence< Any > &seq ) +{ + OUStringBuffer buf(128); + int len = seq.getLength(); + buf.append( "{" ); + for( int i = 0 ; i < len ; i ++ ) + { + OUString element; + seq[i] >>= element; + + if( i > 0 ) + buf.append( "," ); + int strLength = element.getLength(); + buf.append( "\"" ); + for( int j = 0 ; j < strLength ; j ++ ) + { + sal_Unicode c = element[j]; + if( c == '\\' || c == '"' || c == '{' || c == '}' ) + { + buf.append( "\\" ); + } + buf.append( c ); + } + buf.append( "\"" ); + } + buf.append( "}" ); + return buf.makeStringAndClear(); +} + + +std::vector< Any > parseArray( const OUString & str ) +{ + int len = str.getLength(); + bool doubleQuote = false; + int brackets = 0; + int i = 0; + + OUStringBuffer current; + std::vector<Any> elements; + bool doubleQuotedValue = false; + while( i < len ) + { + sal_Unicode c = str[i]; + sal_Unicode cnext = str[i+1]; + if( doubleQuote ) + { + if( '\\' == c ) + { + i ++; + current.append( cnext ); + } + else if( '"' == c ) + { + doubleQuote = false; + doubleQuotedValue = true; // signal, that there was an empty element + } + else + { + current.append( c ); + } + } + else if ( '{' == c ) + { + brackets ++; + } + else if( '}' == c ) + { + brackets --; + if( brackets < 0 ) + { + throw SQLException( + "error during array parsing, didn't expect a } at position " + + OUString::number(i) + " ('" + str + "')", + Reference< XInterface > (), OUString(), 1, Any() ); + } + if( brackets == 0 ) + { + if( !current.isEmpty() || doubleQuotedValue ) + elements.push_back( makeAny( current.makeStringAndClear() ) ); + } + else + { + current.append( c ); + } + } + else if( '"' == c ) + { +// if( current.getLength() != 0 ) +// { +// OUStringBuffer buf; +// buf.appendAscii( "error during array parsing, didn't expect a \" at position " ); +// buf.append( i ); +// buf.append( " ('" ); +// buf.append( str ); +// buf.append( "')" ); +// throw SDBCException( +// buf.makeStringAndClear(), +// Reference< XInterface > (), 1, Any() ); +// } +// else +// { + doubleQuote = true; +// } + } + else if( ',' == c && brackets == 1) + { + doubleQuotedValue = false; + elements.push_back( makeAny( current.makeStringAndClear() ) ); + } + else if( isWhitespace( c ) ) + { + // ignore whitespace without quotes + } + else + { + current.append( c ); + } + i++; + } + return elements; +} + +std::vector< sal_Int32 > parseIntArray( const OUString & str ) +{ + sal_Int32 start = 0; + std::vector<sal_Int32> vec; +// printf( ">%s<\n" , OUStringToOString( str, RTL_TEXTENCODING_UTF8 ).getStr() ); + for( sal_Int32 i = str.indexOf( ' ' ) ; i != -1 ; i = str.indexOf( ' ', start) ) + { + vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) ); +// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 )); + start = i + 1; + } + vec.push_back( rtl_ustr_toInt32( &str.pData->buffer[start], 10 ) ); +// printf( "found %d\n" , rtl_ustr_toInt32( &str.pData->buffer[start], 10 )); + return vec; +} + +void fillAttnum2attnameMap( + Int2StringMap &map, + const Reference< css::sdbc::XConnection > &conn, + const OUString &schema, + const OUString &table ) +{ + Reference< XPreparedStatement > prep = conn->prepareStatement( + "SELECT attname,attnum " + "FROM pg_attribute " + "INNER JOIN pg_class ON attrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "WHERE relname=? AND nspname=?" ); + + Reference< XParameters > paras( prep, UNO_QUERY_THROW ); + paras->setString( 1 , table ); + paras->setString( 2 , schema ); + Reference< XResultSet > rs = prep->executeQuery(); + + Reference< XRow > xRow( rs , UNO_QUERY_THROW ); + while( rs->next() ) + { + map[ xRow->getInt(2) ] = xRow->getString(1); + } +} + +OString extractSingleTableFromSelect( const std::vector< OString > &vec ) +{ + OString ret; + + if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) ) + { + size_t token = 0; + + for( token = 1; token < vec.size() ; token ++ ) + { + if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) ) + { + // found from + break; + } + } + token ++; + + if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) ) + { + token ++; + } + + if( token < vec.size() && vec[token] != "(" ) + { + // it is a table or a function name + OStringBuffer buf(128); + if( '"' == vec[token][0] ) + buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 ); + else + buf.append( vec[token] ); + token ++; + + if( token < vec.size() ) + { + if( vec[token] == "." ) + { + buf.append( vec[token] ); + token ++; + if( token < vec.size() ) + { + if( '"' == vec[token][0] ) + buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 ); + else + buf.append( vec[token] ); + token ++; + } + } + } + + ret = buf.makeStringAndClear(); + // now got my table candidate + + if( token < vec.size() && vec[token] == "(" ) + { + // whoops, it is a function + ret.clear(); + } + else + { + if( token < vec.size() ) + { + if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) ) + { + token += 2; // skip alias + } + } + + if( token < vec.size() ) + { + if( vec[token] == "," ) + { + // whoops, multiple tables are used + ret.clear(); + } + else + { + static const char * forbiddenKeywords[] = + { "join", "natural", "outer", "inner", "left", "right", "full" , nullptr }; + for( int i = 0 ; forbiddenKeywords[i] ; i ++ ) + { + size_t nKeywordLen = strlen(forbiddenKeywords[i]); + if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + vec[token].pData->buffer, vec[token].pData->length, + forbiddenKeywords[i], nKeywordLen, + nKeywordLen ) ) + { + // whoops, it is a join + ret.clear(); + } + } + } + } + } + } + } + return ret; + +} + +OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings) +{ + return (PQserverVersion( settings->pConnection ) < 80000)? + OUString("pg_attrdef.adsrc"): + OUString("pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid, true)"); +} + +css::uno::Sequence< sal_Int32 > string2intarray( const OUString & str ) +{ + css::uno::Sequence< sal_Int32 > ret; + const sal_Int32 strlen = str.getLength(); + if( str.getLength() > 1 ) + { + sal_Int32 start = 0; + sal_uInt32 c; + for (;;) + { + c = str.iterateCodePoints(&start); + if (!iswspace(c)) + break; + if ( start == strlen) + return ret; + } + if ( c != L'{' ) + return ret; + for (;;) + { + c = str.iterateCodePoints(&start); + if ( !iswspace(c) ) + break; + if ( start == strlen) + return ret; + } + if ( c == L'}' ) + return ret; + + std::vector< sal_Int32 > vec; + do + { + OUStringBuffer digits; + do + { + if(!iswspace(c)) + break; + if ( start == strlen) + return ret; + c=str.iterateCodePoints(&start); + } while ( c ); + do + { + if (!iswdigit(c)) + break; + if ( start == strlen) + return ret; + digits.append(OUString(&c, 1)); + c = str.iterateCodePoints(&start); + } while ( c ); + vec.push_back( digits.makeStringAndClear().toInt32() ); + do + { + if(!iswspace(c)) + break; + if ( start == strlen) + return ret; + c = str.iterateCodePoints(&start); + } while ( c ); + if ( c == L'}' ) + break; + if ( str.iterateCodePoints(&start) != L',' ) + return ret; + if ( start == strlen) + return ret; + } while( true ); + // vec is guaranteed non-empty + assert(vec.size() > 0); + ret = css::uno::Sequence< sal_Int32 > ( vec.data() , vec.size() ); + } + return ret; +} + + +Sequence< OUString > convertMappedIntArray2StringArray( + const Int2StringMap &map, const Sequence< sal_Int32 > &intArray ) +{ + Sequence< OUString > ret( intArray.getLength() ); + for( int i = 0; i < intArray.getLength() ; i ++ ) + { + Int2StringMap::const_iterator ii = map.find( intArray[i] ); + if( ii != map.end() ) + ret[i] = ii->second; + } + return ret; +} + + +OUString sqltype2string( const Reference< XPropertySet > & desc ) +{ + OUStringBuffer typeName; + typeName.append( extractStringProperty( desc, getStatics().TYPE_NAME ) ); + sal_Int32 precision = extractIntProperty( desc, getStatics().PRECISION ); + + if( precision ) + { + switch( extractIntProperty( desc, getStatics().TYPE ) ) + { + case css::sdbc::DataType::VARBINARY: + case css::sdbc::DataType::VARCHAR: + case css::sdbc::DataType::CHAR: + { + typeName.append( "(" ); + typeName.append( precision ); + typeName.append( ")" ); + break; + } + case css::sdbc::DataType::DECIMAL: + case css::sdbc::DataType::NUMERIC: + { + typeName.append( "(" ); + typeName.append( precision ); + typeName.append( "," ); + typeName.append( extractIntProperty( desc, getStatics().SCALE ) ); + typeName.append( ")" ); + break; + } + default: + ((void)0); + } + } + return typeName.makeStringAndClear(); +} + + +static void keyType2String( OUStringBuffer & buf, sal_Int32 keyType ) +{ + if( css::sdbc::KeyRule::CASCADE == keyType ) + { + buf.append( "CASCADE " ); + } + else if( css::sdbc::KeyRule::RESTRICT == keyType ) + { + buf.append( "RESTRICT " ); + } + else if( css::sdbc::KeyRule::SET_DEFAULT == keyType ) + { + buf.append( "SET DEFAULT " ); + } + else if( css::sdbc::KeyRule::SET_NULL == keyType ) + { + buf.append( "SET NULL " ); + } + else //if( css::sdbc::KeyRule::NO_ACTION == keyType ) + { + buf.append( "NO ACTION " ); + } +} + +void bufferKey2TableConstraint( + OUStringBuffer &buf, const Reference< XPropertySet > &key, ConnectionSettings *settings ) +{ + Statics &st = getStatics(); + sal_Int32 type = extractIntProperty( key, st.TYPE ); + OUString referencedTable = extractStringProperty( key, st.REFERENCED_TABLE ); + sal_Int32 updateRule = extractIntProperty( key, st.UPDATE_RULE ); + sal_Int32 deleteRule = extractIntProperty( key, st.DELETE_RULE ); + bool foreign = false; + if( type == css::sdbcx::KeyType::UNIQUE ) + { + buf.append( "UNIQUE( " ); + } + else if( type == css::sdbcx::KeyType::PRIMARY ) + { + buf.append( "PRIMARY KEY( " ); + } + else if( type == css::sdbcx::KeyType::FOREIGN ) + { + foreign = true; + buf.append( "FOREIGN KEY( " ); + } + + Reference< XColumnsSupplier > columns( key, UNO_QUERY ); + if( columns.is() ) + { + Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY ); + if( colEnumAccess.is() ) + { + Reference< XEnumeration > colEnum = colEnumAccess->createEnumeration(); + bool first = true; + while(colEnum.is() && colEnum->hasMoreElements() ) + { + if( first ) + { + first = false; + } + else + { + buf.append( ", " ); + } + Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW ); + bufferQuoteIdentifier(buf, extractStringProperty( keyColumn, st.NAME ), settings ); + } + } + } + buf.append( ") " ); + + if( !foreign ) + return; + + buf.append( "REFERENCES " ); + OUString schema; + OUString tableName; + splitConcatenatedIdentifier( referencedTable, &schema, &tableName ); + bufferQuoteQualifiedIdentifier(buf , schema, tableName, settings ); + if(columns.is() ) + { + Reference< XEnumerationAccess > colEnumAccess( columns->getColumns(), UNO_QUERY); + if( colEnumAccess.is() ) + { + buf.append( " (" ); + Reference< XEnumeration > colEnum(colEnumAccess->createEnumeration()); + bool first = true; + while(colEnum.is() && colEnum->hasMoreElements() ) + { + if( first ) + { + first = false; + } + else + { + buf.append( ", " ); + } + Reference< XPropertySet > keyColumn( colEnum->nextElement(), UNO_QUERY_THROW ); + bufferQuoteIdentifier( + buf, extractStringProperty( keyColumn, st.RELATED_COLUMN ), settings ); + } + buf.append( ") " ); + } + } + + buf.append( "ON DELETE " ); + keyType2String( buf, deleteRule ); + buf.append( " ON UPDATE " ); + keyType2String( buf, updateRule ); + +} + +void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery ) +{ + std::vector< OString > vec; + tokenizeSQL( lastQuery, vec ); + + int nSize = vec.size(); +// printf( "1 %d\n", nSize ); + if( !(nSize > 6 && + vec[0].equalsIgnoreAsciiCase( "insert" ) && + vec[1].equalsIgnoreAsciiCase( "into" )) ) + return; + + int n = 2; + +// printf( "1a\n" ); + // skip table name + if( vec[n+1].equalsIgnoreAsciiCase( "." ) ) + { + n +=2; + } + + n ++; + if( !vec[n].equalsIgnoreAsciiCase( "(" ) ) + return; + + std::vector< OString> names; +// printf( "2\n" ); + // extract names + n++; + while( nSize > n && ! vec[n].equalsIgnoreAsciiCase( ")" ) ) + { + names.push_back( vec[n] ); + if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase( "," ) ) + { + n ++; + } + n++; + } + n++; + + // now read the values + if( !(nSize > n +1 && vec[n].equalsIgnoreAsciiCase("VALUES") && + vec[n+1].equalsIgnoreAsciiCase( "(" )) ) + return; + + n +=2; +// printf( "3\n" ); + for (auto& name : names) + { + if (n >= nSize) + break; + + map[name] = vec[n]; + if( nSize > n+1 && vec[n+1].equalsIgnoreAsciiCase(",") ) + { + n ++; + } + n++; + } +} + +OUString querySingleValue( + const css::uno::Reference< css::sdbc::XConnection > &connection, + const OUString &query ) +{ + OUString ret; + Reference< XStatement > stmt = connection->createStatement(); + DisposeGuard guard( stmt ); + Reference< XResultSet > rs = stmt->executeQuery( query ); + Reference< XRow > xRow( rs, UNO_QUERY ); + if( rs->next() ) + ret = xRow->getString( 1 ); + return ret; +} + + +// copied from connectivity/source/dbtools, can't use the function directly +bool implSetObject( const Reference< XParameters >& _rxParameters, + const sal_Int32 _nColumnIndex, const Any& _rValue) +{ + bool bSuccessfullyReRouted = true; + switch (_rValue.getValueTypeClass()) + { + case css::uno::TypeClass_HYPER: + { + _rxParameters->setLong( _nColumnIndex, sal_Int64(0) ); + } + break; + + case css::uno::TypeClass_VOID: + _rxParameters->setNull(_nColumnIndex,css::sdbc::DataType::VARCHAR); + break; + + case css::uno::TypeClass_STRING: + _rxParameters->setString(_nColumnIndex, *o3tl::forceAccess<OUString>(_rValue)); + break; + + case css::uno::TypeClass_BOOLEAN: + _rxParameters->setBoolean(_nColumnIndex, *o3tl::forceAccess<bool>(_rValue)); + break; + + case css::uno::TypeClass_BYTE: + _rxParameters->setByte(_nColumnIndex, *o3tl::forceAccess<sal_Int8>(_rValue)); + break; + + case css::uno::TypeClass_UNSIGNED_SHORT: + case css::uno::TypeClass_SHORT: + _rxParameters->setShort(_nColumnIndex, *o3tl::forceAccess<sal_Int16>(_rValue)); + break; + + case css::uno::TypeClass_CHAR: + _rxParameters->setString(_nColumnIndex, OUString(*o3tl::forceAccess<sal_Unicode>(_rValue))); + break; + + case css::uno::TypeClass_UNSIGNED_LONG: + case css::uno::TypeClass_LONG: + _rxParameters->setInt(_nColumnIndex, *o3tl::forceAccess<sal_Int32>(_rValue)); + break; + + case css::uno::TypeClass_FLOAT: + _rxParameters->setFloat(_nColumnIndex, *o3tl::forceAccess<float>(_rValue)); + break; + + case css::uno::TypeClass_DOUBLE: + _rxParameters->setDouble(_nColumnIndex, *o3tl::forceAccess<double>(_rValue)); + break; + + case css::uno::TypeClass_SEQUENCE: + if (auto s = o3tl::tryAccess<Sequence< sal_Int8 >>(_rValue)) + { + _rxParameters->setBytes(_nColumnIndex, *s); + } + else + bSuccessfullyReRouted = false; + break; + case css::uno::TypeClass_STRUCT: + if (auto s1 = o3tl::tryAccess<css::util::DateTime>(_rValue)) + _rxParameters->setTimestamp(_nColumnIndex, *s1); + else if (auto s2 = o3tl::tryAccess<css::util::Date>(_rValue)) + _rxParameters->setDate(_nColumnIndex, *s2); + else if (auto s3 = o3tl::tryAccess<css::util::Time>(_rValue)) + _rxParameters->setTime(_nColumnIndex, *s3); + else + bSuccessfullyReRouted = false; + break; + + case css::uno::TypeClass_INTERFACE: + { + Reference< css::io::XInputStream > xStream; + if (_rValue >>= xStream) + { + _rValue >>= xStream; + _rxParameters->setBinaryStream(_nColumnIndex, xStream, xStream->available()); + break; + } + [[fallthrough]]; + } + default: + bSuccessfullyReRouted = false; + + } + + return bSuccessfullyReRouted; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_tools.hxx b/connectivity/source/drivers/postgresql/pq_tools.hxx new file mode 100644 index 000000000..af751f8e6 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_tools.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_TOOLS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_TOOLS_HXX + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> + +#include <rtl/ustrbuf.hxx> +#include <rtl/string.hxx> + +#include "pq_connection.hxx" +#include <vector> + +namespace pq_sdbc_driver +{ +bool isWhitespace( sal_Unicode c ); + +OUString concatQualified( const OUString & a, const OUString &b); + +OString OUStringToOString( const OUString& str, ConnectionSettings const *settings); + +void bufferQuoteConstant( OUStringBuffer & buf, const OUString & str, ConnectionSettings *settings ); +void bufferQuoteAnyConstant( OUStringBuffer & buf, const css::uno::Any &val, ConnectionSettings *settings ); + +void bufferEscapeConstant( OUStringBuffer & buf, const OUString & str, ConnectionSettings *settings ); + +OUString sqltype2string( + const css::uno::Reference< css::beans::XPropertySet > & column ); + + +void bufferQuoteQualifiedIdentifier( + OUStringBuffer & buf, const OUString &schema, const OUString &name, ConnectionSettings *settings ); + +void bufferQuoteQualifiedIdentifier( + OUStringBuffer & buf, + const OUString &schema, + const OUString &name, + const OUString &col, + ConnectionSettings *settings ); + +void bufferQuoteIdentifier( OUStringBuffer & buf, const OUString &toQuote, ConnectionSettings *settings ); +void bufferKey2TableConstraint( + OUStringBuffer &buf, + const css::uno::Reference< css::beans::XPropertySet > &key, + ConnectionSettings *settings ); + +OUString extractStringProperty( + const css::uno::Reference< css::beans::XPropertySet > & descriptor, + const OUString &name ); + +sal_Int32 extractIntProperty( + const css::uno::Reference< css::beans::XPropertySet > & descriptor, + const OUString &name ); + +bool extractBoolProperty( + const css::uno::Reference< css::beans::XPropertySet > & descriptor, + const OUString &name ); + +void disposeNoThrow( const css::uno::Reference< css::uno::XInterface > & r ); +void disposeObject( const css::uno::Reference< css::uno::XInterface > & r ); + +OUString extractTableFromInsert( const OUString & sql ); +OString extractSingleTableFromSelect( const std::vector< OString > &vec ); + +OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings); + +void tokenizeSQL( const OString & sql, std::vector< OString > &vec ); +void splitSQL( const OString & sql, std::vector< OString > &vec ); +std::vector< sal_Int32 > parseIntArray( const OUString & str ); +/// @throws css::sdbc::SQLException +std::vector< css::uno::Any > parseArray( const OUString & str ); + +OUString array2String( const css::uno::Sequence< css::uno::Any > &seq ); + +css::uno::Reference< css::sdbc::XConnection > extractConnectionFromStatement( + const css::uno::Reference< css::uno::XInterface > & stmt ); + +void splitConcatenatedIdentifier( const OUString & source, OUString *first, OUString *second); + + +void fillAttnum2attnameMap( + Int2StringMap &map, + const css::uno::Reference< css::sdbc::XConnection > &conn, + const OUString &schema, + const OUString &table ); + +css::uno::Sequence< sal_Int32 > string2intarray( const OUString & str ); + +css::uno::Sequence< OUString > convertMappedIntArray2StringArray( + const Int2StringMap &map, const css::uno::Sequence< sal_Int32> &source ); + +typedef std::unordered_map< OString, OString > String2StringMap; + +OUString querySingleValue( + const css::uno::Reference< css::sdbc::XConnection > &connection, + const OUString &query ); + +void extractNameValuePairsFromInsert( String2StringMap & map, const OString & lastQuery ); +sal_Int32 typeNameToDataType( const OUString &typeName, const OUString &typtype ); + +// copied from connectivity/source/dbtools, can't use the function directly +bool implSetObject( const css::uno::Reference< css::sdbc::XParameters >& _rxParameters, + const sal_Int32 _nColumnIndex, const css::uno::Any& _rValue); + +class DisposeGuard +{ + css::uno::Reference< css::uno::XInterface > d; +public: + explicit DisposeGuard(const css::uno::Reference< css::uno::XInterface > & r ); + ~DisposeGuard(); + +}; + +class TransactionGuard +{ + css::uno::Reference< css::sdbc::XStatement > m_stmt; + bool m_commited; +public: + /// takes over ownership of given statement + explicit TransactionGuard( const css::uno::Reference< css::sdbc::XStatement > &stmt ); + ~TransactionGuard( ); + + void commit(); + void executeUpdate( const OUString & sql ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx b/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx new file mode 100644 index 000000000..880adc647 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_updateableresultset.cxx @@ -0,0 +1,551 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 200? by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> + +#include "pq_updateableresultset.hxx" +#include "pq_resultsetmetadata.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +#include <string.h> + +#include <connectivity/dbconversion.hxx> + +using osl::MutexGuard; + + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::sdbc::XGeneratedResultSet; +using com::sun::star::sdbc::XResultSetMetaDataSupplier; +using com::sun::star::sdbc::SQLException; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XCloseable; +using com::sun::star::sdbc::XColumnLocate; +using com::sun::star::sdbc::XResultSetUpdate; +using com::sun::star::sdbc::XRowUpdate; +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; + +using com::sun::star::beans::XFastPropertySet; +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::XMultiPropertySet; + +using namespace dbtools; + +namespace pq_sdbc_driver +{ + + +css::uno::Reference< css::sdbc::XCloseable > UpdateableResultSet::createFromPGResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **ppSettings, + PGresult *result, + const OUString &schema, + const OUString &table, + const std::vector< OUString > &primaryKey ) +{ + sal_Int32 columnCount = PQnfields( result ); + sal_Int32 rowCount = PQntuples( result ); + std::vector< OUString > columnNames( columnCount ); + for( int i = 0 ; i < columnCount ; i ++ ) + { + char * name = PQfname( result, i ); + columnNames[i] = OUString( name, strlen(name), ConnectionSettings::encoding ); + } + std::vector< std::vector< Any > > data( rowCount ); + + // copy all the data into unicode strings (also binaries, as we yet + // don't know, what a binary is and what not!) + for( int row = 0 ; row < rowCount ; row ++ ) + { + std::vector< Any > aRow( columnCount ); + for( int col = 0 ; col < columnCount ; col ++ ) + { + if( ! PQgetisnull( result, row, col ) ) + { + char * val = PQgetvalue( result, row, col ); + + aRow[col] <<= + OUString( val, strlen( val ), ConnectionSettings::encoding ); + } + } + data[row] = aRow; + } + + UpdateableResultSet *pRS = new UpdateableResultSet( + mutex, owner, columnNames, data, ppSettings, schema, table, primaryKey ); + + Reference <XCloseable > ret = pRS; // give it a refcount + + pRS->m_meta = new ResultSetMetaData( mutex, pRS,nullptr, ppSettings, result, schema, table ); + + PQclear( result ); // we don't need it anymore + + return ret; +} + +css::uno::Any UpdateableResultSet::queryInterface( + const css::uno::Type & reqType ) +{ + Any ret = SequenceResultSet::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< XResultSetUpdate * > ( this ), + static_cast< XRowUpdate * > ( this ) ); + return ret; +} + + +css::uno::Sequence< css::uno::Type > UpdateableResultSet::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<XResultSetUpdate>::get(), + cppu::UnoType<XRowUpdate>::get(), + SequenceResultSet::getTypes()); + + return collection.getTypes(); + +} + +css::uno::Sequence< sal_Int8> UpdateableResultSet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +OUString UpdateableResultSet::buildWhereClause() +{ + OUString ret; + if( !m_primaryKey.empty() ) + { + OUStringBuffer buf( 128 ); + buf.append( " WHERE " ); + for( size_t i = 0 ; i < m_primaryKey.size() ; i ++ ) + { + if( i > 0 ) + buf.append( " AND " ); + sal_Int32 index = findColumn( m_primaryKey[i] ); + bufferQuoteIdentifier( buf, m_primaryKey[i], *m_ppSettings ); + buf.append( " = " ); + bufferQuoteConstant( buf, getString( index ), *m_ppSettings ); + } + ret = buf.makeStringAndClear(); + } + return ret; +} + + +void UpdateableResultSet::insertRow( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + SAL_INFO("connectivity.postgresql", "UpdateableResultSet::insertRow() got called"); + + if( ! m_insertRow ) + throw SQLException( + "pq_resultset.insertRow: moveToInsertRow has not been called !", + *this, OUString(), 1, Any() ); + + OUStringBuffer buf( 128 ); + buf.append( "INSERT INTO " ); + bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings ); + buf.append( " ( " ); + + int columns = 0; + for( UpdateableFieldVector::size_type i = 0 ; i < m_updateableField.size() ; i++ ) + { + if( m_updateableField[i].isTouched ) + { + if( columns > 0 ) + buf.append( ", " ); + columns ++; + bufferQuoteIdentifier( buf, m_columnNames[i], *m_ppSettings); + } + } + buf.append( " ) VALUES ( " ); + + columns = 0; + for(const UpdateableField & i : m_updateableField) + { + if( i.isTouched ) + { + if( columns > 0 ) + buf.append( " , " ); + columns ++; + bufferQuoteAnyConstant( buf, i.value, *m_ppSettings ); + +// OUString val; +// m_updateableField[i].value >>= val; +// buf.append( val ); +// OStringToOUString(val, (*m_ppSettings)->encoding ) ); + } + } + + buf.append( " )" ); + + Reference< XStatement > stmt = + extractConnectionFromStatement(m_owner)->createStatement(); + DisposeGuard dispGuard( stmt ); + stmt->executeUpdate( buf.makeStringAndClear() ); + + // reflect the changes ! + m_rowCount ++; + m_data.resize( m_rowCount ); + m_data[m_rowCount-1] = std::vector< Any > ( m_fieldCount ); + Reference< XGeneratedResultSet > result( stmt, UNO_QUERY ); + if( result.is() ) + { + Reference< XResultSet > rs = result->getGeneratedValues(); + if( rs.is() && rs->next() ) + { + Reference< XColumnLocate > columnLocate( rs, UNO_QUERY ); + Reference< XRow> xRow ( rs, UNO_QUERY ); + for( int i = 0 ; i < m_fieldCount ; i++ ) + { + int field = columnLocate->findColumn( m_columnNames[i] ); + if( field >= 1 ) + { + m_data[m_rowCount-1][i] <<= xRow->getString( field ); +// printf( "adding %s %s\n" , +// OUStringToOString( m_columnNames[i], RTL_TEXTENCODING_ASCII_US).getStr(), +// OUStringToOString( xRow->getString( field ), RTL_TEXTENCODING_ASCII_US).getStr() ); + + } + } + } + else + { + // do the best we can ( DEFAULT and AUTO increment values fail ! ) + for( int i = 0 ; i < m_fieldCount ; i ++ ) + { + if( m_updateableField[i].isTouched ) + m_data[m_rowCount-1][i] = m_updateableField[i].value; + } + } + } + + // cleanup + m_updateableField = UpdateableFieldVector(); +} + +void UpdateableResultSet::updateRow( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + SAL_INFO("connectivity.postgresql", "UpdateableResultSet::updateRow() got called"); + + if( m_insertRow ) + throw SQLException( + "pq_resultset.updateRow: moveToCurrentRow has not been called !", + *this, OUString(), 1, Any() ); + + OUStringBuffer buf( 128 ); + buf.append( "UPDATE " ); + bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings ); + buf.append( "SET " ); + + int columns = 0; + for( UpdateableFieldVector::size_type i = 0; i < m_updateableField.size() ; i ++ ) + { + if( m_updateableField[i].isTouched ) + { + if( columns > 0 ) + buf.append( ", " ); + columns ++; + + buf.append( m_columnNames[i] ); + buf.append( " = " ); + bufferQuoteAnyConstant( buf, m_updateableField[i].value, *m_ppSettings ); +// OUString val; +// m_updateableField[i].value >>= val; +// bufferQuoteConstant( buf, val ): +// buf.append( val ); + } + } + buf.append( buildWhereClause() ); + + Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement(); + DisposeGuard dispGuard( stmt ); + stmt->executeUpdate( buf.makeStringAndClear() ); + + // reflect the changes ! + for( int i = 0 ; i < m_fieldCount ; i ++ ) + { + if( m_updateableField[i].isTouched ) + m_data[m_row][i] = m_updateableField[i].value; + } + m_updateableField = UpdateableFieldVector(); +} + +void UpdateableResultSet::deleteRow( ) +{ + SAL_INFO("connectivity.postgresql", "UpdateableResultSet::deleteRow() got called"); + + if( m_insertRow ) + throw SQLException( + "pq_resultset.deleteRow: deleteRow cannot be called when on insert row !", + *this, OUString(), 1, Any() ); + + if( m_row < 0 || m_row >= m_rowCount ) + { + throw SQLException( + "deleteRow cannot be called on invalid row (" + + OUString::number(m_row) + ")", + *this, OUString(), 0, Any() ); + } + + Reference< XStatement > stmt = extractConnectionFromStatement(m_owner)->createStatement(); + DisposeGuard dispGuard( stmt ); + OUStringBuffer buf( 128 ); + buf.append( "DELETE FROM " ); + bufferQuoteQualifiedIdentifier( buf, m_schema, m_table, *m_ppSettings ); + buf.append( " " ); + buf.append( buildWhereClause() ); + + stmt->executeUpdate( buf.makeStringAndClear() ); + + // reflect the changes ! + for( int i = m_row + 1; i < m_row ; i ++ ) + { + m_data[i-1] = m_data[i]; + } + m_rowCount --; + m_data.resize( m_rowCount ); + } + +void UpdateableResultSet::cancelRowUpdates( ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + m_updateableField = UpdateableFieldVector(); +} + +void UpdateableResultSet::moveToInsertRow( ) +{ + m_insertRow = true; +} + +void UpdateableResultSet::moveToCurrentRow( ) +{ + m_insertRow = false; +} + +void UpdateableResultSet::checkUpdate( sal_Int32 columnIndex) +{ + checkColumnIndex( columnIndex ); + if( m_updateableField.empty() ) + m_updateableField = UpdateableFieldVector( m_fieldCount ); + m_updateableField[columnIndex-1].isTouched = true; +} + +void UpdateableResultSet::updateNull( sal_Int32 columnIndex ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + m_updateableField[columnIndex-1].value = Any(); +} + +void UpdateableResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + Statics &st = getStatics(); + m_updateableField[columnIndex-1].value <<= ( x ? st.TRUE : st.FALSE ); + +} + +void UpdateableResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x ) +{ + updateInt(columnIndex,x); +} + +void UpdateableResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x ) +{ + updateInt( columnIndex, x ); +} + +void UpdateableResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x ) +{ + updateLong( columnIndex, x ); +// MutexGuard guard( m_xMutex->GetMutex() ); +// checkClosed(); +// checkUpdate( columnIndex ); + +// m_updateableField[columnIndex-1].value <<= OUString::valueOf( x ); + +} + +void UpdateableResultSet::updateLong( sal_Int32 columnIndex, sal_Int64 x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + +// OStringBuffer buf( 20 ); +// buf.append( "'" ); +// buf.append( (sal_Int64) x ); +// buf.append( "'" ); + m_updateableField[columnIndex-1].value <<= OUString::number( x ); +} + +void UpdateableResultSet::updateFloat( sal_Int32 columnIndex, float x ) +{ + + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + m_updateableField[columnIndex-1].value <<= OUString::number( x ); +} + +void UpdateableResultSet::updateDouble( sal_Int32 columnIndex, double x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + m_updateableField[columnIndex-1].value <<= OUString::number( x ); +} + +void UpdateableResultSet::updateString( sal_Int32 columnIndex, const OUString& x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + m_updateableField[columnIndex-1].value <<= x; +} + +void UpdateableResultSet::updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + checkClosed(); + checkUpdate( columnIndex ); + + size_t len; + unsigned char * escapedString = + PQescapeBytea( reinterpret_cast<unsigned char const *>(x.getConstArray()), x.getLength(), &len); + if( ! escapedString ) + { + throw SQLException( + "pq_preparedstatement.setBytes: Error during converting bytesequence to an SQL conform string", + *this, OUString(), 1, Any() ); + } +// buf.append( (const char *)escapedString, len -1 ); + + m_updateableField[columnIndex-1].value <<= + OUString( reinterpret_cast<char*>(escapedString), len, RTL_TEXTENCODING_ASCII_US ); + free( escapedString ); +} + +void UpdateableResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x ) +{ + updateString( columnIndex, DBTypeConversion::toDateString( x ) ); +} + +void UpdateableResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x ) +{ + updateString( columnIndex, DBTypeConversion::toTimeString( x ) ); +} + +void UpdateableResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) +{ + updateString( columnIndex, DBTypeConversion::toDateTimeString( x ) ); +} + +void UpdateableResultSet::updateBinaryStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ ) +{ +} + +void UpdateableResultSet::updateCharacterStream( sal_Int32 /* columnIndex */, const css::uno::Reference< css::io::XInputStream >& /* x */, sal_Int32 /* length */ ) +{ +} + +void UpdateableResultSet::updateObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */ ) +{ +} + +void UpdateableResultSet::updateNumericObject( sal_Int32 /* columnIndex */, const css::uno::Any& /* x */, sal_Int32 /* scale */ ) +{ +} + + +Sequence< Type > UpdateableResultSet::getStaticTypes( bool updateable ) +{ + if( updateable ) + { + cppu::OTypeCollection collection( + cppu::UnoType<XResultSetUpdate>::get(), + cppu::UnoType<XRowUpdate>::get(), +// cppu::UnoType<css::sdbcx::XRowLocate>::get(), + getStaticTypes( false /* updateable */ ) ); + return collection.getTypes(); + } + else + { + cppu::OTypeCollection collection( + cppu::UnoType<XResultSet>::get(), + cppu::UnoType<XResultSetMetaDataSupplier>::get(), + cppu::UnoType<XRow>::get(), + cppu::UnoType<XColumnLocate>::get(), + cppu::UnoType<XCloseable>::get(), + cppu::UnoType<XPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<css::lang::XComponent>::get(), // OComponentHelper + cppu::UnoType<css::lang::XTypeProvider>::get(), + cppu::UnoType<css::uno::XAggregation>::get(), + cppu::UnoType<css::uno::XWeak>::get()); + return collection.getTypes(); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx b/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx new file mode 100644 index 000000000..feb3f5322 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_updateableresultset.hxx @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 200? by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_UPDATEABLERESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_UPDATEABLERESULTSET_HXX + +#include "pq_sequenceresultset.hxx" +#include "pq_resultsetmetadata.hxx" + +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> + +namespace pq_sdbc_driver +{ + +struct UpdateableField +{ + UpdateableField( ) + : isTouched(false) + {} + css::uno::Any value; + bool isTouched; +}; + +typedef std::vector< UpdateableField > UpdateableFieldVector; + +class UpdateableResultSet final : + public SequenceResultSet, + public css::sdbc::XResultSetUpdate, + public css::sdbc::XRowUpdate +{ + ConnectionSettings **m_ppSettings; + OUString m_schema; + OUString m_table; + std::vector< OUString > m_primaryKey; + UpdateableFieldVector m_updateableField; + bool m_insertRow; + +private: + UpdateableResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + const std::vector< OUString > &colNames, + const std::vector< std::vector< css::uno::Any > > &data, + ConnectionSettings **ppSettings, + const OUString &schema, + const OUString &table, + const std::vector< OUString > &primaryKey) + : SequenceResultSet( mutex, owner, colNames, data, (*ppSettings)->tc ), + m_ppSettings( ppSettings ), + m_schema( schema ), + m_table( table ), + m_primaryKey( primaryKey ), + m_insertRow( false ) + { + // LEM TODO: this duplicates code in pq_resultset.cxx, except for different value + // of ResultSetConcurrency. Baaad. + // Why is an updatable ResultSet a sequenceresultset in the first place? + // This seems to imply that the whole data is fetched once and kept in memory. BAAAAD. + // LEM TODO: shouldn't these things be inherited from the statement or something like that? + // Positioned update/delete not supported, so no cursor name + // Fetch direction and size are cursor-specific things, so not used now. + // Fetch size not set + m_props[ BASERESULTSET_FETCH_DIRECTION ] <<= css::sdbc::FetchDirection::UNKNOWN; + // No escape processing for now + m_props[ BASERESULTSET_ESCAPE_PROCESSING ] <<= false; + // Bookmarks not implemented for now + m_props[ BASERESULTSET_IS_BOOKMARKABLE ] <<= false; + m_props[ BASERESULTSET_RESULT_SET_CONCURRENCY ] <<= + css::sdbc::ResultSetConcurrency::UPDATABLE; + m_props[ BASERESULTSET_RESULT_SET_TYPE ] <<= + css::sdbc::ResultSetType::SCROLL_INSENSITIVE; + } + + OUString buildWhereClause(); + void checkUpdate( sal_Int32 column ); + +public: + static css::uno::Reference< css::sdbc::XCloseable > createFromPGResultSet( + const ::rtl::Reference< comphelper::RefCountedMutex > & mutex, + const css::uno::Reference< css::uno::XInterface > &owner, + ConnectionSettings **ppSettings, + PGresult *result, + const OUString &schema, + const OUString &table, + const std::vector< OUString > &primaryKey ); + +public: // XInterface + virtual void SAL_CALL acquire() throw() override { SequenceResultSet::acquire(); } + virtual void SAL_CALL release() throw() override { SequenceResultSet::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + +public: // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + +public: + /// @throws css::uno::RuntimeException + static css::uno::Sequence< css::uno::Type > getStaticTypes( bool updateable ); + +}; + + +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_UPDATEABLERESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xbase.cxx b/connectivity/source/drivers/postgresql/pq_xbase.cxx new file mode 100644 index 000000000..1fec4130a --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xbase.cxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/sequence.hxx> + +#include "pq_tools.hxx" +#include "pq_xbase.hxx" + +using osl::MutexGuard; + +using com::sun::star::uno::Any; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Reference; +using com::sun::star::uno::RuntimeException; + +using com::sun::star::beans::Property; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::beans::XPropertySet; + +namespace pq_sdbc_driver +{ + +ReflectionBase::ReflectionBase( + const OUString &implName, + const css::uno::Sequence< OUString > &supportedServices, + const ::rtl::Reference< comphelper::RefCountedMutex >& refMutex, + const css::uno::Reference< css::sdbc::XConnection > &conn, + ConnectionSettings *pSettings, + cppu::IPropertyArrayHelper & props /* must survive this object !*/ ) + : ReflectionBase_BASE( refMutex->GetMutex() ), + OPropertySetHelper( ReflectionBase_BASE::rBHelper ), + m_implName( implName ), + m_supportedServices( supportedServices ), + m_xMutex( refMutex ), + m_conn( conn ), + m_pSettings( pSettings ), + m_propsDesc( props ), + m_values( props.getProperties().getLength() ) +{} + +cppu::IPropertyArrayHelper & ReflectionBase::getInfoHelper() +{ + return m_propsDesc; +} + +sal_Bool ReflectionBase::convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) +{ + + rOldValue = m_values[nHandle]; + rConvertedValue = rValue; // TODO !!! implement correct conversion ! + m_values[nHandle] = rValue; + return true; +} + +void ReflectionBase::setPropertyValue_NoBroadcast_public( + const OUString & name, const css::uno::Any & value ) +{ + sal_Int32 nHandle = m_propsDesc.getHandleByName( name ); + if( -1 == nHandle ) + { + throw css::uno::RuntimeException( + "Unknown property '" + name + "' in " + m_implName, + *this ); + } + setFastPropertyValue_NoBroadcast( nHandle , value ); +} + +void ReflectionBase::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) +{ +// OUString s; +// rValue >>= s; +// printf( "setting value (handle %d):%s\n" , +// nHandle, OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr() ); + m_values[nHandle] = rValue; +} + +void ReflectionBase::getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const +{ + rValue = m_values[nHandle]; +// OUString s; +// rValue >>= s; +// printf( "getting value (handle %d):%s\n" , +// nHandle, OUStringToOString(s, RTL_TEXTENCODING_ASCII_US).getStr() ); + +} + +Reference < css::beans::XPropertySetInfo > ReflectionBase::getPropertySetInfo() +{ + return OPropertySetHelper::createPropertySetInfo( m_propsDesc ); +} + +OUString ReflectionBase::getImplementationName() +{ + return m_implName; +} + +sal_Bool ReflectionBase::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > ReflectionBase::getSupportedServiceNames() +{ + return m_supportedServices; +} + + +Sequence< css::uno::Type > ReflectionBase::getTypes() +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + static Sequence< css::uno::Type > collection( + ::comphelper::concatSequences( + ::cppu::OPropertySetHelper::getTypes(), + ReflectionBase_BASE::getTypes() ) ); + return collection; +} + + +css::uno::Any ReflectionBase::queryInterface( + const css::uno::Type & reqType ) +{ + Any ret = ReflectionBase_BASE::queryInterface( reqType ); + return ret.hasValue() ? ret : OPropertySetHelper::queryInterface( reqType ); + +} + +Sequence< sal_Int8> ReflectionBase::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +void ReflectionBase::copyValuesFrom( const Reference< XPropertySet > & set ) +{ + Reference< XPropertySetInfo > info = set->getPropertySetInfo(); + if( info.is () ) + { + Reference< XPropertySetInfo > myPropInfo = getPropertySetInfo(); + + const Sequence< Property > props = info->getProperties(); + for( Property const & prop : props ) + { + if( myPropInfo->hasPropertyByName( prop.Name ) ) + setPropertyValue_NoBroadcast_public( + prop.Name, set->getPropertyValue( prop.Name ) ); + } + } +} + +OUString ReflectionBase::getName( ) +{ + Statics & st = getStatics(); + if( getInfoHelper().hasPropertyByName( st.SCHEMA_NAME ) ) + return concatQualified( + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ) ); + else + return extractStringProperty( this, getStatics().NAME ); +} + + +void ReflectionBase::setName( const OUString& /* aName */ ) +{ + throw RuntimeException( + "pq_sdbc::ReflectionBase::setName not implemented", + *this ); + //setPropertyValue( getStatics().NAME , makeAny( aName ) ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xbase.hxx b/connectivity/source/drivers/postgresql/pq_xbase.hxx new file mode 100644 index 000000000..6e7ac8413 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xbase.hxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XBASE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XBASE_HXX +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/component.hxx> +#include <cppuhelper/compbase.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XNamed.hpp> + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo, + css::sdbcx::XDataDescriptorFactory, + css::container::XNamed + > ReflectionBase_BASE; + +class ReflectionBase : + public ReflectionBase_BASE, + public cppu::OPropertySetHelper +{ +protected: + const OUString m_implName; + const css::uno::Sequence< OUString > m_supportedServices; + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + css::uno::Reference< css::sdbc::XConnection > m_conn; + ConnectionSettings *m_pSettings; + cppu::IPropertyArrayHelper & m_propsDesc; + std::vector< css::uno::Any > m_values; +public: + ReflectionBase( + const OUString &implName, + const css::uno::Sequence< OUString > &supportedServices, + const ::rtl::Reference< comphelper::RefCountedMutex >& refMutex, + const css::uno::Reference< css::sdbc::XConnection > &conn, + ConnectionSettings *pSettings, + cppu::IPropertyArrayHelper & props /* must survive this object !*/ ); + +public: + void copyValuesFrom( const css::uno::Reference< css::beans::XPropertySet > &set ); + +public: // for initialization purposes only, not exported via an interface ! + void setPropertyValue_NoBroadcast_public( + const OUString & name, const css::uno::Any & value ); + +public: //XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase_BASE::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase_BASE::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // OPropertySetHelper + virtual cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + + void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + // XPropertySet + css::uno::Reference < css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + +public: // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override = 0; + +public: // XNamed + virtual OUString SAL_CALL getName( ) override; + virtual void SAL_CALL setName( const OUString& aName ) override; + +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcolumn.cxx b/connectivity/source/drivers/postgresql/pq_xcolumn.cxx new file mode 100644 index 000000000..c6d98b0fc --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcolumn.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include "pq_xcolumn.hxx" + +using com::sun::star::uno::Reference; + +using com::sun::star::beans::XPropertySet; + +namespace pq_sdbc_driver +{ +Column::Column( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.column.implName, + getStatics().refl.column.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.column.pProps ) +{} + +Reference< XPropertySet > Column::createDataDescriptor( ) +{ + ColumnDescriptor * pColumn = new ColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pColumn->copyValuesFrom( this ); + return Reference< XPropertySet > ( pColumn ); +} + +ColumnDescriptor::ColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.columnDescriptor.implName, + getStatics().refl.columnDescriptor.serviceNames, + refMutex, + connection, + pSettings, + *getStatics().refl.columnDescriptor.pProps ) +{} + +Reference< XPropertySet > ColumnDescriptor::createDataDescriptor( ) +{ + ColumnDescriptor * pColumn = new ColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pColumn ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcolumn.hxx b/connectivity/source/drivers/postgresql/pq_xcolumn.hxx new file mode 100644 index 000000000..ea4e099fc --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcolumn.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XCOLUMN_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XCOLUMN_HXX + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class Column : public ReflectionBase +{ +public: + Column( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + +class ColumnDescriptor : public ReflectionBase +{ +public: + ColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcolumns.cxx b/connectivity/source/drivers/postgresql/pq_xcolumns.cxx new file mode 100644 index 000000000..4edb1aabc --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcolumns.cxx @@ -0,0 +1,555 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> + +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xcolumns.hxx" +#include "pq_xcolumn.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::RuntimeException; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XDatabaseMetaData; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +static Any isCurrency( const OUString & typeName ) +{ + return Any( typeName.equalsIgnoreAsciiCase("money") ); +} + +// static sal_Bool isAutoIncrement8( const OUString & typeName ) +// { +// return typeName.equalsIgnoreAsciiCase("serial8") || +// typeName.equalsIgnoreAsciiCase("bigserial"); +// } + +static Any isAutoIncrement( const OUString & defaultValue ) +{ + bool ret = defaultValue.startsWith( "nextval(" ); +// printf( "%s %d\n", +// OUStringToOString(defaultValue, RTL_TEXTENCODING_ASCII_US).getStr(), +// ret ); +// { +// static const char * const serials[] = +// { +// "serial", "serial4", "serial8", "bigserial", 0 +// }; +// s sal_Bool b = sal_False; +// for( int i = 0; !b && serials[i] ; i ++ ) +// { +// b = b || typeName.equalsIgnoreAsciiCaseAscii( serials[i] ); +// } + return Any ( ret ); +} + +Columns::Columns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName) + : Container( refMutex, origin, pSettings, "COLUMN" ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{} + +Columns::~Columns() +{} + +OUString columnMetaData2SDBCX( + ReflectionBase *pBase, const css::uno::Reference< css::sdbc::XRow > &xRow ) +{ + Statics & st = getStatics(); + + // 1. TABLE_CAT string => table catalog (may be NULL) + // => not supported + // 2. TABLE_SCHEM string => table schema (may be NULL) + // => pg_namespace.nspname + // 3. TABLE_NAME string => table name + // => pg_class.relname + // 4. COLUMN_NAME string => column name + // => pg_attribute.attname + // 5. DATA_TYPE short => SQL type from java.sql.Types + // => pg_type.typname => sdbc.DataType + // 6. TYPE_NAME string => Data source dependent type name, for a UDT the + // type name is fully qualified + // => pg_type.typname + // 7. COLUMN_SIZE long => column size. For char or date types this is + // the maximum number of characters, for numeric + // or decimal types this is precision. + // => pg_type.typlen ( TODO: What is about variable size ? ) + // 8. BUFFER_LENGTH is not used. + // => not used + // 9. DECIMAL_DIGITS long => the number of fractional digits + // => don't know ! TODO ! + // 10. NUM_PREC_RADIX long => Radix (typically either 10 or 2) + // => TODO ?? + // 11. NULLABLE long => is NULL allowed? + // NO_NULLS - might not allow NULL values + // NULABLE - definitely allows NULL values + // NULLABLE_UNKNOWN - nullability unknown + // => pg_attribute.attnotnull + // 12. REMARKS string => comment describing column (may be NULL ) + // => Don't know, there does not seem to exist something like + // that in postgres + // 13. COLUMN_DEF string => default value (may be NULL) + // => pg_type.typdefault + // 14. SQL_DATA_TYPE long => unused + // => empty + // 15. SQL_DATETIME_SUB long => unused + // => empty + // 16. CHAR_OCTET_LENGTH long => for char types the maximum number of + // bytes in the column + // => pg_type.typlen + // 17. ORDINAL_POSITION int => index of column in table (starting at 1) + // pg_attribute.attnum + // 18. IS_NULLABLE string => "NO" means column definitely does not allow + // NULL values; "YES" means the column might + // allow NULL values. An empty string means + // nobody knows. + // => pg_attribute.attnotnull + + static const int COLUMN_NAME = 4; + static const int DATA_TYPE = 5; + static const int TYPE_NAME = 6; + static const int COLUMN_SIZE = 7; + static const int DECIMAL_DIGITS = 9; + static const int IS_NULLABLE = 11; + static const int DESCRIPTION = 12; + static const int DEFAULT_VALUE = 13; + + OUString name = xRow->getString( COLUMN_NAME ); + OUString typeName = xRow->getString( TYPE_NAME ); + + pBase->setPropertyValue_NoBroadcast_public( + st.NAME, makeAny( name ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.TYPE, makeAny( xRow->getInt( DATA_TYPE ) ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.TYPE_NAME, makeAny( typeName ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.PRECISION, makeAny( xRow->getInt( COLUMN_SIZE ) ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.SCALE, makeAny( xRow->getInt( DECIMAL_DIGITS ) ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.IS_NULLABLE, makeAny( xRow->getInt( IS_NULLABLE ) ) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.DEFAULT_VALUE, makeAny( xRow->getString( DEFAULT_VALUE ) ) ); + +// pBase->setPropertyValue_NoBroadcast_public( +// st.DESCRIPTION, makeAny( xRow->getString( DESCRIPTION ) ) ); + +// if( pBase->getPropertySetInfo()->hasPropertyByName( st.HELP_TEXT ) ) +// pBase->setPropertyValue_NoBroadcast_public( +// st.HELP_TEXT, makeAny( xRow->getString( DESCRIPTION ) ) ); +// else // for key columns, etc. ... + pBase->setPropertyValue_NoBroadcast_public( + st.DESCRIPTION, makeAny( xRow->getString( DESCRIPTION ) ) ); + + + // maybe a better criterion than the type name can be found in future + pBase->setPropertyValue_NoBroadcast_public( + st.IS_AUTO_INCREMENT, isAutoIncrement(xRow->getString( DEFAULT_VALUE )) ); + + pBase->setPropertyValue_NoBroadcast_public( + st.IS_CURRENCY, isCurrency( typeName)); + return name; +} + + +// class CommentChanger : public cppu::WeakImplHelper< XPropertyChangeListener > +// { +// ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; +// css::uno::Reference< css::sdbc::XConnection > m_connection; +// ConnectionSettings *m_pSettings; +// OUString m_schema; +// OUString m_table; +// OUString m_column; + +// public: +// CommentChanger( +// const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, +// const css::uno::Reference< css::sdbc::XConnection > & connection, +// ConnectionSettings *pSettings, +// const OUString & schema, +// const OUString & table, +// const OUString & column ) : +// m_xMutex( refMutex ), +// m_connection( connection ), +// m_pSettings( pSettings ), +// m_schema ( schema ), +// m_table ( table ), +// m_column ( column ) +// {} + + +// // Methods +// virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) throw (css::uno::RuntimeException) +// { +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// m_connection.clear(); +// } +// // Methods +// virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) throw (css::uno::RuntimeException) +// { +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// OUStringBuffer buf( 128 ); +// OUString comment; +// evt.NewValue >>= comment; +// buf.append( "COMMENT ON COLUMN" ); +// bufferQuoteQualifiedIdentifier( buf, m_schema, m_table , m_column ); +// buf.append( "IS " ); +// bufferQuoteConstant( buf, comment,m_pSettings->encoding); + +// printf( "changing comment of column %s to %s\n", +// OUStringToOString( m_column, RTL_TEXTENCODING_ASCII_US ).getStr(), +// OUStringToOString( comment, RTL_TEXTENCODING_ASCII_US ).getStr() ); + +// m_connection->createStatement()->executeUpdate( buf.makeStringAndClear() ); +// } +// }; + +void Columns::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.Columns get refreshed for table " << m_schemaName << "." << m_tableName); + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + Statics &st = getStatics(); + Reference< XDatabaseMetaData > meta = m_origin->getMetaData(); + + Reference< XResultSet > rs = + meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT ); + + DisposeGuard disposeIt( rs ); + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + + m_values.clear(); + int columnIndex = 0; + while( rs->next() ) + { + Column * pColumn = + new Column( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pColumn; + + OUString name = columnMetaData2SDBCX( pColumn, xRow ); +// pColumn->addPropertyChangeListener( +// st.HELP_TEXT, +// new CommentChanger( +// m_xMutex, +// m_origin, +// m_pSettings, +// m_schemaName, +// m_tableName, +// name ) ); + + { + m_values.push_back( makeAny( prop ) ); + map[ name ] = columnIndex; + ++columnIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + nullptr, anyEx ); + } + fire( RefreshedBroadcaster( *this ) ); +} + + +void alterColumnByDescriptor( + const OUString & schemaName, + const OUString & tableName, + ConnectionSettings *settings, + const Reference< XStatement > &stmt, + const css::uno::Reference< css::beans::XPropertySet > & past, + const css::uno::Reference< css::beans::XPropertySet > & future) +{ + Statics & st = getStatics(); + +// if( past->getPropertyValue( st.TABLE_NAME ) != future->getPropertyValue( st.TABLE_NAME ) || +// past->getPropertyValue( st.SCHEMA_NAME ) != future->getPropertyValue( st.SCHEMA_NAME )) +// { +// OUStringBuffer buf(128); +// buf.append( "Can't move column " ); +// buf.append( extractStringProperty( past, st.COLUMN_NAME ) ); +// buf.append( " from table " ); +// buf.append( extractStringProperty( past, st.TABLE_NAME ) ); +// buf.append( " to table " ); +// buf.append( extractStringProperty( past, st.TABLE_NAME ) ); +// throw SQLException( buf.makeStringAndClear() ); +// } + +// OUString tableName = extractStringProperty( past, st.TABLE_NAME ); +// OUString schemaName = extractStringProperty( past, st.SCHEMA_NAME ); + OUString pastColumnName = extractStringProperty( past, st.NAME ); + OUString futureColumnName = extractStringProperty( future, st.NAME ); + OUString pastTypeName = sqltype2string( past ); + OUString futureTypeName = sqltype2string( future ); + + TransactionGuard transaction( stmt ); + + OUStringBuffer buf( 128 ); + if( ! pastColumnName.getLength()) + { + // create a new column + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings ); + buf.append( "ADD COLUMN" ); + bufferQuoteIdentifier( buf, futureColumnName, settings ); + buf.append( futureTypeName ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + else + { + if( pastTypeName != futureTypeName ) + { + throw RuntimeException( + "Can't modify column types, drop the column and create a new one" ); + } + + if( pastColumnName != futureColumnName ) + { + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings ); + buf.append( "RENAME COLUMN" ); + bufferQuoteIdentifier( buf, pastColumnName, settings ); + buf.append( "TO" ); + bufferQuoteIdentifier( buf, futureColumnName, settings ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + } + + OUString futureDefaultValue = extractStringProperty( future, st.DEFAULT_VALUE ); + OUString pastDefaultValue = extractStringProperty( past, st.DEFAULT_VALUE ); + if( futureDefaultValue != pastDefaultValue ) + { + buf.truncate(); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings ); + buf.append( "ALTER COLUMN" ); + bufferQuoteIdentifier( buf, futureColumnName, settings ); + buf.append( "SET DEFAULT " ); + // LEM TODO: check out + // default value is not quoted, caller needs to quote himself (otherwise + // how to pass e.g. nextval('something' ) ???? + buf.append( futureDefaultValue ); +// bufferQuoteConstant( buf, defaultValue, encoding ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + + sal_Int32 futureNullable = extractIntProperty( future, st.IS_NULLABLE ); + sal_Int32 pastNullable = extractIntProperty( past, st.IS_NULLABLE ); + if( futureNullable != pastNullable ) + { + buf.truncate(); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName, settings ); + buf.append( "ALTER COLUMN" ); + bufferQuoteIdentifier( buf, futureColumnName, settings ); + if( futureNullable == css::sdbc::ColumnValue::NO_NULLS ) + { + buf.append( "SET" ); + } + else + { + buf.append( "DROP" ); + } + buf.append( " NOT NULL" ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + +// OUString futureComment = extractStringProperty( future, st.HELP_TEXT ); +// OUString pastComment = extractStringProperty( past, st.HELP_TEXT ); +// printf( "past Comment %s, futureComment %s\n", +// OUStringToOString( pastComment, RTL_TEXTENCODING_ASCII_US ).getStr(), +// OUStringToOString( futureComment, RTL_TEXTENCODING_ASCII_US ).getStr() ); + OUString futureComment = extractStringProperty( future, st.DESCRIPTION ); + OUString pastComment = extractStringProperty( past, st.DESCRIPTION ); + + if( futureComment != pastComment ) + { + buf.truncate(); + buf.append( "COMMENT ON COLUMN" ); + bufferQuoteQualifiedIdentifier( buf, schemaName, tableName , futureColumnName, settings ); + buf.append( "IS " ); + bufferQuoteConstant( buf, futureComment, settings ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + transaction.commit(); +} + +void Columns::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& future ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + Reference< XPropertySet > past = createDataDescriptor(); + past->setPropertyValue( st.IS_NULLABLE, makeAny( css::sdbc::ColumnValue::NULLABLE ) ); + alterColumnByDescriptor( + m_schemaName, m_tableName, m_pSettings, m_origin->createStatement() , past, future ); + + refresh(); +} + +// void Columns::dropByName( const OUString& elementName ) +// throw (css::sdbc::SQLException, +// css::container::NoSuchElementException, +// css::uno::RuntimeException) +// { +// String2IntMap::const_iterator ii = m_name2index.find( elementName ); +// if( ii == m_name2index.end() ) +// { +// OUStringBuffer buf( 128 ); +// buf.appendAscii( "Column " ); +// buf.append( elementName ); +// buf.appendAscii( " is unknown in table " ); +// buf.append( m_schemaName ); +// buf.appendAscii( "." ); +// buf.append( m_tableName ); +// buf.appendAscii( ", so it can't be dropped" ); +// throw css::container::NoSuchElementException( +// buf.makeStringAndClear(), *this ); +// } +// dropByIndex( ii->second ); +// } + +void Columns::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || index >= static_cast<sal_Int32>(m_values.size()) ) + { + throw css::lang::IndexOutOfBoundsException( + "COLUMNS: Index out of range (allowed 0 to " + + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + Statics &st = getStatics(); + OUString name; + set->getPropertyValue( st.NAME ) >>= name; + + OUStringBuffer update( 128 ); + update.append( "ALTER TABLE ONLY"); + bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName, m_pSettings ); + update.append( "DROP COLUMN" ); + bufferQuoteIdentifier( update, name, m_pSettings ); + Reference< XStatement > stmt = m_origin->createStatement( ); + DisposeGuard disposeIt( stmt ); + stmt->executeUpdate( update.makeStringAndClear() ); + + Container::dropByIndex( index ); +} + + +css::uno::Reference< css::beans::XPropertySet > Columns::createDataDescriptor() +{ + return new ColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Columns::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + Columns **ppColumns) +{ + *ppColumns = new Columns( + refMutex, origin, pSettings, schemaName, tableName ); + Reference< css::container::XNameAccess > ret = *ppColumns; + (*ppColumns)->refresh(); + + return ret; +} + + +ColumnDescriptors::ColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, "COLUMN-DESCRIPTOR" ) +{} + + +Reference< css::beans::XPropertySet > ColumnDescriptors::createDataDescriptor() +{ + return new ColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcolumns.hxx b/connectivity/source/drivers/postgresql/pq_xcolumns.hxx new file mode 100644 index 000000000..ab8c47914 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcolumns.hxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XCOLUMNS_HXX + +#include "pq_xcontainer.hxx" +#include "pq_xbase.hxx" + +namespace com::sun::star::sdbc { class XRow; } + +namespace pq_sdbc_driver +{ + +void alterColumnByDescriptor( + const OUString & schemaName, + const OUString & tableName, + ConnectionSettings *settings, + const css::uno::Reference< css::sdbc::XStatement > &stmt, + const css::uno::Reference< css::beans::XPropertySet > & past, + const css::uno::Reference< css::beans::XPropertySet > & future); + +OUString columnMetaData2SDBCX( + ReflectionBase *pBase, const css::uno::Reference< css::sdbc::XRow > &xRow ); + +class Columns final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + +public: // instances Columns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + Columns **pColumns); + +private: + Columns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + + + virtual ~Columns() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +// public: // XDrop +// virtual void SAL_CALL dropByName( const OUString& elementName ) +// throw (css::sdbc::SQLException, +// css::container::NoSuchElementException, +// css::uno::RuntimeException); + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class ColumnDescriptors : public Container +{ +public: + ColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcontainer.cxx b/connectivity/source/drivers/postgresql/pq_xcontainer.cxx new file mode 100644 index 000000000..06323615f --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcontainer.cxx @@ -0,0 +1,408 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <cppuhelper/implbase.hxx> + +#include "pq_xcontainer.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::Type; +using com::sun::star::uno::XInterface; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::RuntimeException; + +using com::sun::star::container::NoSuchElementException; +using com::sun::star::container::XEnumeration; +using com::sun::star::container::XContainerListener; +using com::sun::star::container::ContainerEvent; +using com::sun::star::lang::IndexOutOfBoundsException; +using com::sun::star::lang::XEventListener; + + +namespace pq_sdbc_driver +{ + +namespace { + +class ReplacedBroadcaster : public EventBroadcastHelper +{ + ContainerEvent m_event; +public: + ReplacedBroadcaster( + const Reference< XInterface > & source, + const OUString & name, + const Any & newElement, + const OUString & oldElement ) : + m_event( source, makeAny( name ), newElement, makeAny(oldElement) ) + {} + + virtual void fire( XEventListener * listener ) const override + { + static_cast<XContainerListener*>(listener)->elementReplaced( m_event ); + } + virtual Type getType() const override + { + return cppu::UnoType<XContainerListener>::get(); + } +}; + +class InsertedBroadcaster : public EventBroadcastHelper +{ +public: + ContainerEvent m_event; + InsertedBroadcaster( + const Reference< XInterface > & source, + const OUString & name, + const Any & newElement ) : + m_event( source, makeAny( name ), newElement, Any() ) + {} + + virtual void fire( XEventListener * listener ) const override + { + static_cast<XContainerListener*>(listener)->elementInserted( m_event ); + } + + virtual Type getType() const override + { + return cppu::UnoType<XContainerListener>::get(); + } +}; + +class RemovedBroadcaster : public EventBroadcastHelper +{ +public: + ContainerEvent m_event; + RemovedBroadcaster( + const Reference< XInterface > & source, + const OUString & name) : + m_event( source, makeAny( name ), Any(), Any() ) + {} + + virtual void fire( XEventListener * listener ) const override + { + static_cast<XContainerListener*>(listener)->elementRemoved( m_event ); + } + + virtual Type getType() const override + { + return cppu::UnoType<XContainerListener>::get(); + } +}; + +} + +Container::Container( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &type) + : ContainerBase( refMutex->GetMutex() ), + m_xMutex( refMutex ), + m_pSettings( pSettings ), + m_origin( origin ), + m_type( type ) +{ +} + +Any Container::getByName( const OUString& aName ) +{ + String2IntMap::const_iterator ii = m_name2index.find( aName ); + if( ii == m_name2index.end() ) + { + throw NoSuchElementException( + "Element " + aName + " unknown in " + m_type + "-Container", + *this ); + } + OSL_ASSERT( ii->second >= 0 && ii->second < static_cast<int>(m_values.size()) ); + return m_values[ ii->second ]; +} + +Sequence< OUString > Container::getElementNames( ) +{ + Sequence< OUString > ret( m_values.size() ); + for( const auto& [rName, rIndex] : m_name2index ) + { + // give element names in index order ! + ret[rIndex] = rName; + } + return ret; +} + +sal_Bool Container::hasByName( const OUString& aName ) +{ + return m_name2index.find( aName ) != m_name2index.end(); +} + // Methods +Type Container::getElementType( ) +{ + return Type(); +} + +sal_Bool Container::hasElements( ) +{ + return ! m_name2index.empty(); +} + +Any Container::getByIndex( sal_Int32 Index ) +{ + if( Index < 0 || Index >= static_cast<sal_Int32>(m_values.size()) ) + { + throw IndexOutOfBoundsException( + "Index " + OUString::number( Index ) + + " out of range for " + m_type + "-Container, expected 0 <= x <= " + + OUString::number(m_values.size() -1), + *this ); + } + return m_values[Index]; +} + +sal_Int32 Container::getCount() +{ + return m_values.size(); +} + +namespace { + +class ContainerEnumeration : public ::cppu::WeakImplHelper< XEnumeration > +{ + std::vector< css::uno::Any > m_vec; + sal_Int32 m_index; +public: + explicit ContainerEnumeration( const std::vector< css::uno::Any > &vec ) + : m_vec( vec ), + m_index( -1 ) + {} + +public: + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements( ) override; + virtual css::uno::Any SAL_CALL nextElement( ) override; + +}; + +} + +sal_Bool ContainerEnumeration::hasMoreElements() +{ + return static_cast<int>(m_vec.size()) > m_index +1; +} + +css::uno::Any ContainerEnumeration::nextElement() +{ + if( ! hasMoreElements() ) + { + throw NoSuchElementException( + "NoSuchElementException during enumeration", *this ); + } + m_index ++; + return m_vec[m_index]; +} + +Reference< XEnumeration > Container::createEnumeration( ) +{ + return new ContainerEnumeration( m_values ); +} + +void Container::addRefreshListener( + const css::uno::Reference< css::util::XRefreshListener >& l ) +{ + rBHelper.addListener( cppu::UnoType<decltype(l)>::get() , l ); +} + +void Container::removeRefreshListener( + const css::uno::Reference< css::util::XRefreshListener >& l ) +{ + rBHelper.removeListener( cppu::UnoType<decltype(l)>::get() , l ); +} + +void Container::disposing() +{ + m_origin.clear(); +} + +void Container::rename( const OUString &oldName, const OUString &newName ) +{ + Any newValue; + { + osl::MutexGuard guard ( m_xMutex->GetMutex() ); + String2IntMap::iterator ii = m_name2index.find( oldName ); + if( ii != m_name2index.end() ) + { + sal_Int32 nIndex = ii->second; + newValue = m_values[nIndex]; + m_name2index.erase( ii ); + m_name2index[ newName ] = nIndex; + } + } + fire( ReplacedBroadcaster( *this, newName, newValue, oldName ) ); + fire( RefreshedBroadcaster( *this ) ); +} + +void Container::dropByName( const OUString& elementName ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + String2IntMap::const_iterator ii = m_name2index.find( elementName ); + if( ii == m_name2index.end() ) + { + throw css::container::NoSuchElementException( + "Column " + elementName + " is unknown in " + + m_type + " container, so it can't be dropped", + *this ); + } + dropByIndex( ii->second ); +} + +void Container::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || index >=static_cast<sal_Int32>(m_values.size()) ) + { + throw css::lang::IndexOutOfBoundsException( + "Index out of range (allowed 0 to " + + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + + ") in " + m_type, + *this ); + } + + OUString name; + String2IntMap::iterator ii = std::find_if(m_name2index.begin(), m_name2index.end(), + [&index](const String2IntMap::value_type& rEntry) { return rEntry.second == index; }); + if (ii != m_name2index.end()) + { + name = ii->first; + m_name2index.erase( ii ); + } + + for( int i = index +1 ; i < static_cast<int>(m_values.size()) ; i ++ ) + { + m_values[i-1] = m_values[i]; + + // I know, this is expensive, but don't want to maintain another map ... + ii = std::find_if(m_name2index.begin(), m_name2index.end(), + [&i](const String2IntMap::value_type& rEntry) { return rEntry.second == i; }); + if (ii != m_name2index.end()) + { + ii->second = i-1; + } + } + m_values.resize( m_values.size() - 1 ); + + fire( RemovedBroadcaster( *this, name ) ); +} + +void Container::append( + const OUString & name, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) + +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + if( hasByName( name ) ) + { + throw css::container::ElementExistException( + "a " + m_type + " with name " + name + " already exists in this container", + *this ); + } + + int index = m_values.size(); + m_values.push_back( makeAny( descriptor ) ); + m_name2index[name] = index; + + fire( InsertedBroadcaster( *this, name, makeAny( descriptor ) ) ); +} + +void Container::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor) +{ + append( extractStringProperty( descriptor, getStatics().NAME ), descriptor ); +} + + +void Container::addContainerListener( + const css::uno::Reference< css::container::XContainerListener >& l ) +{ + rBHelper.addListener( cppu::UnoType<decltype(l)>::get() , l ); +} + +void Container::removeContainerListener( + const css::uno::Reference< css::container::XContainerListener >& l ) +{ + rBHelper.removeListener( cppu::UnoType<decltype(l)>::get() , l ); +} + + +void Container::fire( const EventBroadcastHelper &helper ) +{ + cppu::OInterfaceContainerHelper *container = rBHelper.getContainer( helper.getType() ); + if( !container ) + return; + + cppu::OInterfaceIteratorHelper iterator( * container ); + while( iterator.hasMoreElements() ) + { + try + { + helper.fire( static_cast<XEventListener *>(iterator.next()) ); + } + catch ( css::uno::RuntimeException & ) + { + OSL_ENSURE( false, "exception caught" ); + // loose coupling, a runtime exception shall not break anything + // TODO: log away as warning ! + } + catch( css::uno::Exception & ) + { + OSL_ENSURE( false, "exception from listener flying through" ); + throw; + } + } + +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xcontainer.hxx b/connectivity/source/drivers/postgresql/pq_xcontainer.hxx new file mode 100644 index 000000000..f53b0303a --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xcontainer.hxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XCONTAINER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XCONTAINER_HXX +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XContainer.hpp> + +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XDrop.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> + +#include <com/sun/star/util/XRefreshable.hpp> + +#include <cppuhelper/compbase.hxx> + +#include <unordered_map> + +#include "pq_connection.hxx" +#include "pq_statics.hxx" + +namespace pq_sdbc_driver +{ + +class EventBroadcastHelper +{ +public: + virtual void fire(css::lang::XEventListener * listener) const = 0; + virtual css::uno::Type getType() const = 0; + virtual ~EventBroadcastHelper(){}; +}; + +class RefreshedBroadcaster : public EventBroadcastHelper +{ + css::lang::EventObject m_event; +public: + explicit RefreshedBroadcaster(const css::uno::Reference< css::uno::XInterface > & source ) : + m_event( source ) + {} + + virtual void fire( css::lang::XEventListener * listener ) const override + { + static_cast<css::util::XRefreshListener*>(listener)->refreshed( m_event ); + } + + virtual css::uno::Type getType() const override + { + return cppu::UnoType< + css::util::XRefreshListener>::get(); + } +}; + +typedef std::unordered_map +< + OUString, + sal_Int32 +> String2IntMap; + +typedef ::cppu::WeakComponentImplHelper +< + css::container::XNameAccess, + css::container::XIndexAccess, + css::container::XEnumerationAccess, + css::sdbcx::XAppend, + css::sdbcx::XDrop, + css::util::XRefreshable, + css::sdbcx::XDataDescriptorFactory, + css::container::XContainer +> ContainerBase; + +class /* abstract */ Container : public ContainerBase +{ +protected: + ::rtl::Reference< comphelper::RefCountedMutex > m_xMutex; + ConnectionSettings *m_pSettings; + css::uno::Reference< css::sdbc::XConnection > m_origin; + String2IntMap m_name2index; // maps the element name to an index + std::vector< css::uno::Any > m_values; // contains the real values + OUString m_type; + +public: + Container( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString & type // for exception messages + ); + +public: // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override; + virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override; + +public: // XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > + SAL_CALL createEnumeration( ) override; + +public: // XNameAccess + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override; + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override; + // Methods + virtual css::uno::Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + + +public: // XAppend + // Must be overridden in Non-Descriptors. May be overridden in descriptors, when + // PropertySet.NAME != container name + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + // helper method ! + /// @throws css::container::ElementExistException + void append( + const OUString & str, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ); + + +public: // XDrop + virtual void SAL_CALL dropByName( const OUString& elementName ) override; + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override = 0; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override {} + virtual void SAL_CALL addRefreshListener( + const css::uno::Reference< css::util::XRefreshListener >& l ) override; + virtual void SAL_CALL removeRefreshListener( + const css::uno::Reference< css::util::XRefreshListener >& l ) override; + +public: + // Methods + virtual void SAL_CALL addContainerListener( + const css::uno::Reference< css::container::XContainerListener >& xListener ) override; + virtual void SAL_CALL removeContainerListener( + const css::uno::Reference< css::container::XContainerListener >& xListener ) override; + +public: + virtual void SAL_CALL disposing() override; + +public: + void rename( const OUString & oldName, const OUString &newName ); + +protected: + void fire( const EventBroadcastHelper & helper ); +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindex.cxx b/connectivity/source/drivers/postgresql/pq_xindex.cxx new file mode 100644 index 000000000..c340484a1 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindex.cxx @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include "pq_xindex.hxx" +#include "pq_xindexcolumns.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +using com::sun::star::container::XNameAccess; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + + +namespace pq_sdbc_driver +{ +Index::Index( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings, + const OUString & schemaName, + const OUString & tableName ) + : ReflectionBase( + getStatics().refl.index.implName, + getStatics().refl.index.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.index.pProps ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{} + +Reference< XPropertySet > Index::createDataDescriptor( ) +{ + IndexDescriptor * pIndex = new IndexDescriptor( + m_xMutex, m_conn, m_pSettings ); + pIndex->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pIndex ); +} + +Reference< XNameAccess > Index::getColumns( ) +{ + if( ! m_indexColumns.is() ) + { + Sequence< OUString > columnNames; + getPropertyValue( getStatics().PRIVATE_COLUMN_INDEXES ) >>= columnNames; + OUString indexName = extractStringProperty( this, getStatics().NAME ); + m_indexColumns = IndexColumns::create( + m_xMutex, m_conn, m_pSettings, m_schemaName, + m_tableName, indexName, columnNames ); + } + return m_indexColumns; +} + +Sequence<Type > Index::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> Index::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any Index::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XColumnsSupplier * > ( this ) ); + return ret; +} + + +IndexDescriptor::IndexDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.indexDescriptor.implName, + getStatics().refl.indexDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.indexDescriptor.pProps ) +{} + +Reference< XPropertySet > IndexDescriptor::createDataDescriptor( ) +{ + IndexDescriptor * pIndex = new IndexDescriptor( + m_xMutex, m_conn, m_pSettings ); + pIndex->copyValuesFrom( this ); + return Reference< XPropertySet > ( pIndex ); +} + +Reference< XNameAccess > IndexDescriptor::getColumns( ) +{ + if( ! m_indexColumns.is() ) + { + m_indexColumns = IndexColumnDescriptors::create( + m_xMutex, m_conn, m_pSettings ); +// Sequence< OUString > columnNames; +// getPropertyValue( getStatics().PRIVATE_COLUMN_INDEXES ) >>= columnNames; +// OUString indexName = extractStringProperty( this, getStatics().NAME ); +// m_indexColumns = IndexColumns::create( +// m_xMutex, m_conn, m_pSettings, m_schemaName, +// m_tableName, indexName, columnNames ); + } + return m_indexColumns; +} + +Sequence<Type > IndexDescriptor::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> IndexDescriptor::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any IndexDescriptor::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XColumnsSupplier * > ( this ) ); + return ret; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindex.hxx b/connectivity/source/drivers/postgresql/pq_xindex.hxx new file mode 100644 index 000000000..26e561363 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindex.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XINDEX_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XINDEX_HXX + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class Index : public ReflectionBase, + public css::sdbcx::XColumnsSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_indexColumns; + + OUString m_schemaName; + OUString m_tableName; + +public: + Index( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + +public: // XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +class IndexDescriptor : public ReflectionBase, + public css::sdbcx::XColumnsSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_indexColumns; + +public: + IndexDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx b/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx new file mode 100644 index 000000000..58b36234b --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexcolumn.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include "pq_xindexcolumn.hxx" + +using com::sun::star::uno::Reference; + +using com::sun::star::beans::XPropertySet; + +namespace pq_sdbc_driver +{ +IndexColumn::IndexColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.indexColumn.implName, + getStatics().refl.indexColumn.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.indexColumn.pProps ) +{} + +Reference< XPropertySet > IndexColumn::createDataDescriptor( ) +{ + IndexColumnDescriptor * pIndexColumn = new IndexColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pIndexColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pIndexColumn ); +} + + +IndexColumnDescriptor::IndexColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.indexColumnDescriptor.implName, + getStatics().refl.indexColumnDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.indexColumnDescriptor.pProps ) +{} + +Reference< XPropertySet > IndexColumnDescriptor::createDataDescriptor( ) +{ + IndexColumnDescriptor * pIndexColumn = new IndexColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pIndexColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pIndexColumn ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx b/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx new file mode 100644 index 000000000..5e7ae8d4f --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexcolumn.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XINDEXCOLUMN_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XINDEXCOLUMN_HXX + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class IndexColumn : public ReflectionBase +{ +public: + IndexColumn( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + +class IndexColumnDescriptor : public ReflectionBase +{ +public: + IndexColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx b/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx new file mode 100644 index 000000000..12acb6f32 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexcolumns.cxx @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <vector> + +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xcolumns.hxx" +#include "pq_xindexcolumns.hxx" +#include "pq_xindexcolumn.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XDatabaseMetaData; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +IndexColumns::IndexColumns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const OUString &indexName, + const css::uno::Sequence< OUString > &columns ) + : Container( refMutex, origin, pSettings, "INDEX_COLUMN" ), + m_schemaName( schemaName ), + m_tableName( tableName ), + m_indexName( indexName ), + m_columns( columns ) +{} + +IndexColumns::~IndexColumns() +{} + +static sal_Int32 findInSequence( const Sequence< OUString > & seq , const OUString &str) +{ + int index; + for( index = 0 ; index < seq.getLength() ; index ++ ) + { + if( str == seq[index] ) + break; + } + return index; +} + +void IndexColumns::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.IndexColumns get refreshed for index " << m_indexName); + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + Statics &st = getStatics(); + Reference< XDatabaseMetaData > meta = m_origin->getMetaData(); + + Reference< XResultSet > rs = + meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT ); + + DisposeGuard disposeIt( rs ); + Reference< XRow > xRow( rs , UNO_QUERY ); + m_values.clear(); + m_values.resize( m_columns.getLength() ); + + while( rs->next() ) + { + OUString columnName = xRow->getString( 4 ); + + sal_Int32 index = findInSequence( m_columns, columnName ); + if( index >= m_columns.getLength() ) + continue; + + IndexColumn * pIndexColumn = + new IndexColumn( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pIndexColumn; + + columnMetaData2SDBCX( pIndexColumn, xRow ); + pIndexColumn->setPropertyValue_NoBroadcast_public( + st.IS_ASCENDING , makeAny( false ) ); + + m_values[ index ] <<= prop; + m_name2index[ columnName ] = index; + } + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void IndexColumns::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& /*future*/ ) +{ + throw css::sdbc::SQLException( + "SDBC-POSTGRESQL: IndexesColumns.appendByDescriptor not yet implemented", + *this, OUString(), 1, Any() ); +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// Statics & st = getStatics(); +// Reference< XPropertySet > past = createDataDescriptor(); +// past->setPropertyValue( st.IS_NULLABLE, makeAny( css::sdbc::ColumnValue::NULLABLE ) ); +// alterColumnByDescriptor( +// m_schemaName, m_tableName, m_pSettings->encoding, m_origin->createStatement() , past, future ); + +} + +void IndexColumns::dropByName( const OUString& ) +{ + throw css::sdbc::SQLException( + "SDBC-POSTGRESQL: IndexesColumns.dropByName not yet implemented", + *this, OUString(), 1, Any() ); +// String2IntMap::const_iterator ii = m_name2index.find( elementName ); +// if( ii == m_name2index.end() ) +// { +// OUStringBuffer buf( 128 ); +// buf.appendAscii( "Column " ); +// buf.append( elementName ); +// buf.appendAscii( " is unknown in table " ); +// buf.append( m_schemaName ); +// buf.appendAscii( "." ); +// buf.append( m_tableName ); +// buf.appendAscii( ", so it can't be dropped" ); +// throw css::container::NoSuchElementException( +// buf.makeStringAndClear(), *this ); +// } +// dropByIndex( ii->second ); +} + +void IndexColumns::dropByIndex( sal_Int32 ) +{ + throw css::sdbc::SQLException( + "SDBC-POSTGRESQL: IndexesColumns.dropByIndex not yet implemented", + *this, OUString(), 1, Any() ); +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// if( index < 0 || index >= m_values.getLength() ) +// { +// OUStringBuffer buf( 128 ); +// buf.appendAscii( "COLUMNS: Index out of range (allowed 0 to " ); +// buf.append((sal_Int32)(m_values.getLength() -1) ); +// buf.appendAscii( ", got " ); +// buf.append( index ); +// buf.appendAscii( ")" ); +// throw css::lang::IndexOutOfBoundsException( +// buf.makeStringAndClear(), *this ); +// } + +// Reference< XPropertySet > set; +// m_values[index] >>= set; +// Statics &st = getStatics(); +// OUString name; +// set->getPropertyValue( st.NAME ) >>= name; + +// OUStringBuffer update( 128 ); +// update.appendAscii( "ALTER TABLE ONLY"); +// bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName ); +// update.appendAscii( "DROP COLUMN" ); +// bufferQuoteIdentifier( update, name ); +// Reference< XStatement > stmt = m_origin->createStatement( ); +// DisposeGuard disposeIt( stmt ); +// stmt->executeUpdate( update.makeStringAndClear() ); + +} + + +Reference< css::beans::XPropertySet > IndexColumns::createDataDescriptor() +{ + return new IndexColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > IndexColumns::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const OUString &indexName, + const Sequence< OUString > &columns ) +{ + IndexColumns *pIndexColumns = new IndexColumns( + refMutex, origin, pSettings, schemaName, tableName, indexName, columns ); + Reference< css::container::XNameAccess > ret = pIndexColumns; + pIndexColumns->refresh(); + + return ret; +} + + +IndexColumnDescriptors::IndexColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) + : Container( refMutex, origin, pSettings, getStatics().INDEX_COLUMN ) +{} + +Reference< css::container::XNameAccess > IndexColumnDescriptors::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) +{ + return new IndexColumnDescriptors( refMutex, origin, pSettings ); +} + +css::uno::Reference< css::beans::XPropertySet > IndexColumnDescriptors::createDataDescriptor() +{ + return new IndexColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx b/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx new file mode 100644 index 000000000..353b75ddb --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexcolumns.hxx @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XINDEXCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XINDEXCOLUMNS_HXX + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +class IndexColumns final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + OUString m_indexName; + css::uno::Sequence< OUString > m_columns; + +public: // instances IndexColumns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const OUString &indexName, + const css::uno::Sequence< OUString > &columns ); + +private: + IndexColumns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const OUString &indexName, + const css::uno::Sequence< OUString > &columns ); + + virtual ~IndexColumns() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByName( const OUString& elementName ) override; + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class IndexColumnDescriptors final : public Container +{ + +public: // instances IndexColumns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +private: + IndexColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexes.cxx b/connectivity/source/drivers/postgresql/pq_xindexes.cxx new file mode 100644 index 000000000..2f6df914f --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexes.cxx @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xindexes.hxx" +#include "pq_xindex.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; + +using com::sun::star::container::XEnumerationAccess; +using com::sun::star::container::XEnumeration; + + +using com::sun::star::sdbcx::XColumnsSupplier; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XParameters; +using com::sun::star::sdbc::XPreparedStatement; + +namespace pq_sdbc_driver +{ + +Indexes::Indexes( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName) + : Container( refMutex, origin, pSettings, getStatics().KEY ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{ +} + +Indexes::~Indexes() +{} + +void Indexes::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.Indexes get refreshed for table " << m_schemaName << "." << m_tableName); + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Int2StringMap column2NameMap; + fillAttnum2attnameMap( column2NameMap, m_origin, m_schemaName, m_tableName ); + + // see XDatabaseMetaData::getIndexInfo() + Reference< XPreparedStatement > stmt = m_origin->prepareStatement( + "SELECT nspname, " // 1 + "pg_class.relname, " // 2 + "class2.relname, " // 3 + "indisclustered, " // 4 + "indisunique, " // 5 + "indisprimary, " // 6 + "indkey " // 7 + "FROM pg_index INNER JOIN pg_class ON indrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "INNER JOIN pg_class as class2 ON pg_index.indexrelid = class2.oid " + "WHERE nspname = ? AND pg_class.relname = ?" ); + + Reference< XParameters > params( stmt, UNO_QUERY); + params->setString( 1, m_schemaName ); + params->setString( 2, m_tableName ); + Reference< XResultSet > rs = stmt->executeQuery(); + + Reference< XRow > row( rs, UNO_QUERY ); + String2IntMap map; + m_values.clear(); + sal_Int32 index = 0; + while( rs->next() ) + { + // C_SCHEMA = 1 + // C_TABLENAME = 2 + static const sal_Int32 C_INDEXNAME = 3; + static const sal_Int32 C_IS_CLUSTERED = 4; + static const sal_Int32 C_IS_UNIQUE = 5; + static const sal_Int32 C_IS_PRIMARY = 6; + static const sal_Int32 C_COLUMNS = 7; + OUString currentIndexName = row->getString( C_INDEXNAME ); + Index *pIndex = + new Index( m_xMutex, m_origin, m_pSettings, + m_schemaName, m_tableName ); + + bool isUnique = row->getBoolean( C_IS_UNIQUE ); + bool isPrimary = row->getBoolean( C_IS_PRIMARY ); + bool isClusterd = row->getBoolean( C_IS_CLUSTERED ); + Reference< css::beans::XPropertySet > prop = pIndex; + pIndex->setPropertyValue_NoBroadcast_public( + st.IS_UNIQUE, Any( isUnique ) ); + pIndex->setPropertyValue_NoBroadcast_public( + st.IS_PRIMARY_KEY_INDEX, Any( isPrimary ) ); + pIndex->setPropertyValue_NoBroadcast_public( + st.IS_CLUSTERED, Any( isClusterd ) ); + pIndex->setPropertyValue_NoBroadcast_public( + st.NAME, makeAny( currentIndexName ) ); + + std::vector< sal_Int32 > seq = parseIntArray( row->getString( C_COLUMNS ) ); + Sequence< OUString > columnNames(seq.size()); + for( size_t columns = 0 ; columns < seq.size() ; columns ++ ) + { + columnNames[columns] = column2NameMap[ seq[columns] ]; + } + + pIndex->setPropertyValue_NoBroadcast_public( + st.PRIVATE_COLUMN_INDEXES, makeAny( columnNames )); + + { + m_values.push_back( makeAny( prop ) ); + map[ currentIndexName ] = index; + ++index; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void Indexes::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + Statics & st = getStatics(); + OUString name = extractStringProperty( descriptor, st.NAME ); + + bool isUnique = extractBoolProperty( descriptor, st.IS_UNIQUE ); + + OUStringBuffer buf( 128 ); + + buf.append( "CREATE " ); + if( isUnique ) + buf.append( "UNIQUE " ); + buf.append( "INDEX " ); + bufferQuoteIdentifier( buf, name, m_pSettings ); + buf.append( " ON " ); + bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings ); + + buf.append( " ( " ); + + Reference< XColumnsSupplier > columns( descriptor, UNO_QUERY ); + if( columns.is() ) + { + Reference< XEnumerationAccess > access( columns->getColumns(), UNO_QUERY ); + if( access.is() ) + { + Reference< XEnumeration > xEnum( access->createEnumeration() ); + bool first = true; + while( xEnum.is() && xEnum->hasMoreElements() ) + { + Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY ); + if( first ) + { + first = false; + } + else + { + buf.append( ", " ); + } + buf.append( extractStringProperty( column, st.NAME ) ); + } + } + } + buf.append( " ) " ); + + m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() ); + refresh(); +} + +void Indexes::dropByIndex( sal_Int32 index ) +{ + + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || index >= static_cast<sal_Int32>(m_values.size()) ) + { + throw css::lang::IndexOutOfBoundsException( + "Indexes: Index out of range (allowed 0 to " + + OUString::number( m_values.size() -1 ) + + ", got " + OUString::number( index ) + + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + Statics &st = getStatics(); + + OUStringBuffer buf( 128 ); + buf.append( "DROP INDEX " ); + bufferQuoteIdentifier( buf, extractStringProperty( set, st.NAME ), m_pSettings ); + m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() ); + + Container::dropByIndex( index ); +} + + +css::uno::Reference< css::beans::XPropertySet > Indexes::createDataDescriptor() +{ + return new IndexDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Indexes::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString & schemaName, + const OUString & tableName) +{ + Indexes *pIndexes = new Indexes( refMutex, origin, pSettings, schemaName, tableName ); + Reference< css::container::XNameAccess > ret = pIndexes; + pIndexes->refresh(); + return ret; +} + + +IndexDescriptors::IndexDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) + : Container( refMutex, origin, pSettings, getStatics().INDEX ) +{} + +Reference< css::container::XNameAccess > IndexDescriptors::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) +{ + return new IndexDescriptors( refMutex, origin, pSettings ); +} + +css::uno::Reference< css::beans::XPropertySet > IndexDescriptors::createDataDescriptor() +{ + return new IndexDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xindexes.hxx b/connectivity/source/drivers/postgresql/pq_xindexes.hxx new file mode 100644 index 000000000..7991058f5 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xindexes.hxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XINDEXES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XINDEXES_HXX + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ +class Indexes final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + +public: // instances Columns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + +private: + Indexes( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + + virtual ~Indexes() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class IndexDescriptors final : public Container +{ +public: // instances IndexDescriptors 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +private: + IndexDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; + +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkey.cxx b/connectivity/source/drivers/postgresql/pq_xkey.cxx new file mode 100644 index 000000000..ed0b2669e --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkey.cxx @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include "pq_xkey.hxx" +#include "pq_xkeycolumns.hxx" +#include "pq_statics.hxx" + +using com::sun::star::container::XNameAccess; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + + +namespace pq_sdbc_driver +{ +Key::Key( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings, + const OUString & schemaName, + const OUString & tableName ) + : ReflectionBase( + getStatics().refl.key.implName, + getStatics().refl.key.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.key.pProps ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{} + +Reference< XPropertySet > Key::createDataDescriptor( ) +{ + KeyDescriptor * pKeyDescriptor = new KeyDescriptor( + m_xMutex, m_conn, m_pSettings ); + pKeyDescriptor->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pKeyDescriptor ); +} + +Reference< XNameAccess > Key::getColumns( ) +{ + // TODO: cash columns object ! + if( !m_keyColumns.is() ) + { + Sequence< OUString > columnNames, foreignColumnNames; + getPropertyValue( getStatics().PRIVATE_COLUMNS ) >>= columnNames; + getPropertyValue( getStatics().PRIVATE_FOREIGN_COLUMNS ) >>= foreignColumnNames; + + m_keyColumns = KeyColumns::create( + m_xMutex, m_conn, m_pSettings, m_schemaName, + m_tableName, columnNames, foreignColumnNames ); + } + return m_keyColumns; +} + +Sequence<Type > Key::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> Key::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any Key::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XColumnsSupplier * > ( this ) ); + return ret; +} + + +KeyDescriptor::KeyDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.keyDescriptor.implName, + getStatics().refl.keyDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.keyDescriptor.pProps ) +{ +} + +Reference< XPropertySet > KeyDescriptor::createDataDescriptor( ) +{ + KeyDescriptor * pKeyDescriptor = new KeyDescriptor( + m_xMutex, m_conn, m_pSettings ); + pKeyDescriptor->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pKeyDescriptor ); +} + +Reference< XNameAccess > KeyDescriptor::getColumns( ) +{ + // TODO: cash columns object ! + if( !m_keyColumns.is() ) + { + m_keyColumns = new KeyColumnDescriptors( m_xMutex, m_conn, m_pSettings ); + } + return m_keyColumns; +} + +Sequence<Type > KeyDescriptor::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> KeyDescriptor::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any KeyDescriptor::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XColumnsSupplier * > ( this ) ); + return ret; +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkey.hxx b/connectivity/source/drivers/postgresql/pq_xkey.hxx new file mode 100644 index 000000000..3174d1892 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkey.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XKEY_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XKEY_HXX + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class Key : public ReflectionBase, + public css::sdbcx::XColumnsSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_keyColumns; + + OUString m_schemaName; + OUString m_tableName; + +public: + Key( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + +public: // XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +class KeyDescriptor : public ReflectionBase, public css::sdbcx::XColumnsSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_keyColumns; + +public: + KeyDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ); + +public: // XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; +}; + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx b/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx new file mode 100644 index 000000000..9eea45204 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeycolumn.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include "pq_xkeycolumn.hxx" + +using com::sun::star::uno::Reference; + +using com::sun::star::beans::XPropertySet; + +namespace pq_sdbc_driver +{ +KeyColumn::KeyColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.keycolumn.implName, + getStatics().refl.keycolumn.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.keycolumn.pProps ) +{} + +Reference< XPropertySet > KeyColumn::createDataDescriptor( ) +{ + KeyColumnDescriptor * pKeyColumn = new KeyColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pKeyColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pKeyColumn ); +} + +KeyColumnDescriptor::KeyColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.keycolumnDescriptor.implName, + getStatics().refl.keycolumnDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.keycolumnDescriptor.pProps ) +{} + +Reference< XPropertySet > KeyColumnDescriptor::createDataDescriptor( ) +{ + KeyColumnDescriptor * pKeyColumn = new KeyColumnDescriptor( + m_xMutex, m_conn, m_pSettings ); + pKeyColumn->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pKeyColumn ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx b/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx new file mode 100644 index 000000000..14baf7f66 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeycolumn.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XKEYCOLUMN_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XKEYCOLUMN_HXX + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> + +#include "pq_connection.hxx" +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class KeyColumn : public ReflectionBase +{ +public: + KeyColumn( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + +class KeyColumnDescriptor : public ReflectionBase +{ +public: + KeyColumnDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + +}; + + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx b/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx new file mode 100644 index 000000000..890b57fa7 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeycolumns.cxx @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xcolumns.hxx" +#include "pq_xkeycolumns.hxx" +#include "pq_xkeycolumn.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XDatabaseMetaData; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +KeyColumns::KeyColumns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const Sequence< OUString > &columnNames, + const Sequence< OUString > &foreignColumnNames ) + : Container( refMutex, origin, pSettings, "KEY_COLUMN" ), + m_schemaName( schemaName ), + m_tableName( tableName ), + m_columnNames( columnNames ), + m_foreignColumnNames( foreignColumnNames ) +{} + +KeyColumns::~KeyColumns() +{} + + +void KeyColumns::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.KeyColumns get refreshed for table " << m_schemaName << "." << m_tableName); + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + Statics &st = getStatics(); + Reference< XDatabaseMetaData > meta = m_origin->getMetaData(); + + Reference< XResultSet > rs = + meta->getColumns( Any(), m_schemaName, m_tableName, st.cPERCENT ); + + DisposeGuard disposeIt( rs ); + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + + m_values.clear(); + sal_Int32 columnIndex = 0; + while( rs->next() ) + { + OUString columnName = xRow->getString( 4 ); + + int keyindex; + for( keyindex = 0 ; keyindex < m_columnNames.getLength() ; keyindex ++ ) + { + if( columnName == m_columnNames[keyindex] ) + break; + } + if( m_columnNames.getLength() == keyindex ) + continue; + + KeyColumn * pKeyColumn = + new KeyColumn( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pKeyColumn; + + OUString name = columnMetaData2SDBCX( pKeyColumn, xRow ); + if( keyindex < m_foreignColumnNames.getLength() ) + { + pKeyColumn->setPropertyValue_NoBroadcast_public( + st.RELATED_COLUMN, makeAny( m_foreignColumnNames[keyindex]) ); + } + + { + m_values.push_back( makeAny( prop ) ); + map[ name ] = columnIndex; + ++columnIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void KeyColumns::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& ) +{ + throw css::sdbc::SQLException( + "KeyColumns::appendByDescriptor not implemented yet", + *this, OUString(), 1, Any() ); + +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// Statics & st = getStatics(); +// Reference< XPropertySet > past = createDataDescriptor(); +// past->setPropertyValue( st.IS_NULLABLE, makeAny( css::sdbc::ColumnValue::NULLABLE ) ); +// alterColumnByDescriptor( +// m_schemaName, m_tableName, m_pSettings->encoding, m_origin->createStatement() , past, future ); + +} + + +void KeyColumns::dropByIndex( sal_Int32 ) +{ + throw css::sdbc::SQLException( + "KeyColumns::dropByIndex not implemented yet", + *this, OUString(), 1, Any() ); +// osl::MutexGuard guard( m_xMutex->GetMutex() ); +// if( index < 0 || index >= m_values.getLength() ) +// { +// OUStringBuffer buf( 128 ); +// buf.appendAscii( "COLUMNS: Index out of range (allowed 0 to " ); +// buf.append((sal_Int32)(m_values.getLength() -1) ); +// buf.appendAscii( ", got " ); +// buf.append( index ); +// buf.appendAscii( ")" ); +// throw css::lang::IndexOutOfBoundsException( +// buf.makeStringAndClear(), *this ); +// } + +// Reference< XPropertySet > set; +// m_values[index] >>= set; +// Statics &st = getStatics(); +// OUString name; +// set->getPropertyValue( st.NAME ) >>= name; + +// OUStringBuffer update( 128 ); +// update.appendAscii( "ALTER TABLE ONLY"); +// bufferQuoteQualifiedIdentifier( update, m_schemaName, m_tableName ); +// update.appendAscii( "DROP COLUMN" ); +// bufferQuoteIdentifier( update, name ); +// Reference< XStatement > stmt = m_origin->createStatement( ); +// DisposeGuard disposeIt( stmt ); +// stmt->executeUpdate( update.makeStringAndClear() ); + +} + + +Reference< css::beans::XPropertySet > KeyColumns::createDataDescriptor() +{ + return new KeyColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > KeyColumns::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const Sequence< OUString > &columnNames , + const Sequence< OUString > &foreignColumnNames ) +{ + KeyColumns *pKeyColumns = new KeyColumns( + refMutex, origin, pSettings, schemaName, tableName, columnNames, foreignColumnNames ); + Reference< css::container::XNameAccess > ret = pKeyColumns; + pKeyColumns->refresh(); + + return ret; +} + + +KeyColumnDescriptors::KeyColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, "KEY_COLUMN" ) +{} + +Reference< css::beans::XPropertySet > KeyColumnDescriptors::createDataDescriptor() +{ + return new KeyColumnDescriptor( m_xMutex, m_origin, m_pSettings ); +} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx b/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx new file mode 100644 index 000000000..0ada98aa4 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeycolumns.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XKEYCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XKEYCOLUMNS_HXX + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +class KeyColumns final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + css::uno::Sequence< OUString > m_columnNames; + css::uno::Sequence< OUString > m_foreignColumnNames; + +public: // instances KeyColumns 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const css::uno::Sequence< OUString > &keyColumns, + const css::uno::Sequence< OUString > &foreignColumnNames ); + +private: + KeyColumns( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName, + const css::uno::Sequence< OUString > &keyColumns, + const css::uno::Sequence< OUString > &foreignColumnNames); + + virtual ~KeyColumns() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class KeyColumnDescriptors : public Container +{ +public: + KeyColumnDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeys.cxx b/connectivity/source/drivers/postgresql/pq_xkeys.cxx new file mode 100644 index 000000000..2297b557e --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeys.cxx @@ -0,0 +1,290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <com/sun/star/sdbcx/KeyType.hpp> +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xkeys.hxx" +#include "pq_xkey.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + + +using css::beans::XPropertySet; + +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; + + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XParameters; +using com::sun::star::sdbc::XPreparedStatement; + +namespace pq_sdbc_driver +{ + +Keys::Keys( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName) + : Container( refMutex, origin, pSettings, getStatics().KEY ), + m_schemaName( schemaName ), + m_tableName( tableName ) +{} + +Keys::~Keys() +{} + +static sal_Int32 string2keytype( const OUString &type ) +{ + sal_Int32 ret = css::sdbcx::KeyType::UNIQUE; + if ( type == "p" ) + ret = css::sdbcx::KeyType::PRIMARY; + else if ( type == "f" ) + ret = css::sdbcx::KeyType::FOREIGN; + return ret; +} + +static sal_Int32 string2keyrule( const OUString & rule ) +{ + sal_Int32 ret = css::sdbc::KeyRule::NO_ACTION; + if( rule == "r" ) + ret = css::sdbc::KeyRule::RESTRICT; + else if( rule == "c" ) + ret = css::sdbc::KeyRule::CASCADE; + else if( rule == "n" ) + ret = css::sdbc::KeyRule::SET_NULL; + else if( rule == "d" ) + ret = css::sdbc::KeyRule::SET_DEFAULT; + return ret; +} + +void Keys::refresh() +{ + try + { + SAL_INFO("connectivity.postgresql", "sdbcx.Keys get refreshed for table " << m_schemaName << "." << m_tableName); + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Int2StringMap mainMap; + fillAttnum2attnameMap( mainMap, m_origin, m_schemaName, m_tableName ); + + Reference< XPreparedStatement > stmt = m_origin->prepareStatement( + "SELECT conname, " // 1 + "contype, " // 2 + "confupdtype, " // 3 + "confdeltype, " // 4 + "class2.relname, " // 5 + "nmsp2.nspname, " // 6 + "conkey," // 7 + "confkey " // 8 + "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid " + "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid " + "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid " + "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid " + "WHERE pg_class.relname = ? AND pg_namespace.nspname = ?" ); + + Reference< XParameters > paras( stmt, UNO_QUERY ); + paras->setString( 1 , m_tableName ); + paras->setString( 2 , m_schemaName ); + Reference< XResultSet > rs = stmt->executeQuery(); + + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + m_values.clear(); + int keyIndex = 0; + while( rs->next() ) + { + Key * pKey = + new Key( m_xMutex, m_origin, m_pSettings , m_schemaName, m_tableName ); + Reference< css::beans::XPropertySet > prop = pKey; + + pKey->setPropertyValue_NoBroadcast_public( + st.NAME, makeAny( xRow->getString( 1 ) ) ); + sal_Int32 keyType = string2keytype( xRow->getString(2) ); + pKey->setPropertyValue_NoBroadcast_public( st.TYPE, makeAny( keyType ) ); + pKey->setPropertyValue_NoBroadcast_public( + st.UPDATE_RULE, makeAny( string2keyrule( xRow->getString(3) ) ) ); + pKey->setPropertyValue_NoBroadcast_public( + st.DELETE_RULE, makeAny( string2keyrule( xRow->getString(4) ) ) ); + pKey->setPropertyValue_NoBroadcast_public( + st.PRIVATE_COLUMNS, + makeAny( + convertMappedIntArray2StringArray( + mainMap, + string2intarray( xRow->getString( 7 ) ) ) ) ); + + if( css::sdbcx::KeyType::FOREIGN == keyType ) + { + OUStringBuffer buf( 128 ); + buf.append( xRow->getString( 6 ) ).append( "." ).append( xRow->getString( 5 ) ); + pKey->setPropertyValue_NoBroadcast_public( + st.REFERENCED_TABLE, makeAny( buf.makeStringAndClear() ) ); + + Int2StringMap foreignMap; + fillAttnum2attnameMap( foreignMap, m_origin, xRow->getString(6), xRow->getString(5)); + pKey->setPropertyValue_NoBroadcast_public( + st.PRIVATE_FOREIGN_COLUMNS, + makeAny( + convertMappedIntArray2StringArray( + foreignMap, + string2intarray( xRow->getString(8) ) ) ) ); + } + + + { + map[ xRow->getString( 1 ) ] = keyIndex; + m_values.push_back( makeAny( prop ) ); + ++keyIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void Keys::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + OUStringBuffer buf( 128 ); + buf.append( "ALTER TABLE " ); + bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings ); + buf.append( " ADD " ); + bufferKey2TableConstraint( buf, descriptor, m_pSettings ); + + Reference< XStatement > stmt = + m_origin->createStatement(); + stmt->executeUpdate( buf.makeStringAndClear() ); +} + + +void Keys::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || index >= static_cast<sal_Int32>(m_values.size()) ) + { + throw css::lang::IndexOutOfBoundsException( + "TABLES: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + ")", + *this ); + } + + + Reference< XPropertySet > set; + m_values[index] >>= set; + + OUStringBuffer buf( 128 ); + buf.append( "ALTER TABLE " ); + bufferQuoteQualifiedIdentifier( buf, m_schemaName, m_tableName, m_pSettings ); + buf.append( " DROP CONSTRAINT " ); + bufferQuoteIdentifier( buf, extractStringProperty( set , getStatics().NAME ), m_pSettings ); + m_origin->createStatement()->executeUpdate( buf.makeStringAndClear() ); + + + Container::dropByIndex( index ); +} + + +css::uno::Reference< css::beans::XPropertySet > Keys::createDataDescriptor() +{ + return new KeyDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XIndexAccess > Keys::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString & schemaName, + const OUString & tableName) +{ + Keys *pKeys = new Keys( refMutex, origin, pSettings, schemaName, tableName ); + Reference< css::container::XIndexAccess > ret = pKeys; + pKeys->refresh(); + + return ret; +} + +KeyDescriptors::KeyDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) + : Container( refMutex, origin, pSettings, getStatics().KEY ) +{} + +Reference< css::container::XIndexAccess > KeyDescriptors::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings) +{ + return new KeyDescriptors( refMutex, origin, pSettings ); +} + +css::uno::Reference< css::beans::XPropertySet > KeyDescriptors::createDataDescriptor() +{ + return new KeyDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xkeys.hxx b/connectivity/source/drivers/postgresql/pq_xkeys.hxx new file mode 100644 index 000000000..aedd46b57 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xkeys.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XKEYS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XKEYS_HXX + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ +class Keys final : public Container +{ + OUString m_schemaName; + OUString m_tableName; + +public: // instances Columns 'exception safe' + static css::uno::Reference< css::container::XIndexAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + +private: + Keys( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + const OUString &schemaName, + const OUString &tableName); + + virtual ~Keys() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + + +class KeyDescriptors final : public Container +{ +public: // instances Columns 'exception safe' + static css::uno::Reference< css::container::XIndexAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +private: + KeyDescriptors( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xtable.cxx b/connectivity/source/drivers/postgresql/pq_xtable.cxx new file mode 100644 index 000000000..82b66a316 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xtable.cxx @@ -0,0 +1,395 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +#include "pq_xtable.hxx" +#include "pq_xtables.hxx" +#include "pq_xviews.hxx" +#include "pq_xindexes.hxx" +#include "pq_xkeys.hxx" +#include "pq_xcolumns.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +using osl::MutexGuard; + +using com::sun::star::container::XNameAccess; +using com::sun::star::container::XIndexAccess; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ +Table::Table( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.table.implName, + getStatics().refl.table.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.table.pProps ), + m_pColumns( nullptr ) +{} + +Reference< XPropertySet > Table::createDataDescriptor( ) +{ + TableDescriptor * pTable = new TableDescriptor( + m_xMutex, m_conn, m_pSettings ); + pTable->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pTable ); +} + +Reference< XNameAccess > Table::getColumns( ) +{ + if( ! m_columns.is() ) + { + m_columns = Columns::create( + m_xMutex, + m_conn, + m_pSettings, + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ), + &m_pColumns); + } + return m_columns; +} + +Reference< XNameAccess > Table::getIndexes() +{ + if( ! m_indexes.is() ) + { + m_indexes = ::pq_sdbc_driver::Indexes::create( + m_xMutex, + m_conn, + m_pSettings, + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ) ); + } + return m_indexes; +} + +Reference< XIndexAccess > Table::getKeys( ) +{ + if( ! m_keys.is() ) + { + m_keys = ::pq_sdbc_driver::Keys::create( + m_xMutex, + m_conn, + m_pSettings, + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ) ); + } + return m_keys; +} + +void Table::rename( const OUString& newName ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + OUString oldName = extractStringProperty(this,st.NAME ); + OUString schema = extractStringProperty(this,st.SCHEMA_NAME ); + OUString fullOldName = concatQualified( schema, oldName ); + + OUString newTableName; + OUString newSchemaName; + // OOo2.0 passes schema + dot + new-table-name while + // OO1.1.x passes new Name without schema + // in case name contains a dot, it is interpreted as schema.tablename + if( newName.indexOf( '.' ) >= 0 ) + { + splitConcatenatedIdentifier( newName, &newSchemaName, &newTableName ); + } + else + { + newTableName = newName; + newSchemaName = schema; + } + OUString fullNewName = concatQualified( newSchemaName, newTableName ); + + if( extractStringProperty( this, st.TYPE ) == st.VIEW && m_pSettings->views.is() ) + { + // maintain view list (really strange API !) + Any a = m_pSettings->pViewsImpl->getByName( fullOldName ); + Reference< css::sdbcx::XRename > Xrename; + a >>= Xrename; + if( Xrename.is() ) + { + Xrename->rename( newName ); + setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, makeAny(newSchemaName) ); + } + } + else + { + if( newSchemaName != schema ) + { + // try new schema name first + try + { + OUStringBuffer buf(128); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings ); + buf.append( "SET SCHEMA" ); + bufferQuoteIdentifier( buf, newSchemaName, m_pSettings ); + Reference< XStatement > statement = m_conn->createStatement(); + statement->executeUpdate( buf.makeStringAndClear() ); + setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, makeAny(newSchemaName) ); + disposeNoThrow( statement ); + schema = newSchemaName; + } + catch( css::sdbc::SQLException &e ) + { + OUString buf( e.Message + "(NOTE: Only postgresql server >= V8.1 support changing a table's schema)" ); + e.Message = buf; + throw; + } + + } + if( newTableName != oldName ) // might also be just the change of a schema name + { + OUStringBuffer buf(128); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings ); + buf.append( "RENAME TO" ); + bufferQuoteIdentifier( buf, newTableName, m_pSettings ); + Reference< XStatement > statement = m_conn->createStatement(); + statement->executeUpdate( buf.makeStringAndClear() ); + disposeNoThrow( statement ); + } + } + setPropertyValue_NoBroadcast_public( st.NAME, makeAny(newTableName) ); + // inform the container of the name change ! + if( m_pSettings->tables.is() ) + { + m_pSettings->pTablesImpl->rename( fullOldName, fullNewName ); + } +} + +void Table::alterColumnByName( + const OUString& colName, + const Reference< XPropertySet >& descriptor ) +{ + Reference< css::container::XNameAccess > columns = getColumns(); + + OUString newName = extractStringProperty(descriptor, getStatics().NAME ); + ::pq_sdbc_driver::alterColumnByDescriptor( + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ), + m_pSettings, + m_conn->createStatement(), + Reference< css::beans::XPropertySet>( columns->getByName( colName ), UNO_QUERY) , + descriptor ); + + if( colName != newName ) + { +// m_pColumns->rename( colName, newName ); + m_pColumns->refresh(); + } +} + +void Table::alterColumnByIndex( + sal_Int32 index, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + Reference< css::container::XIndexAccess > columns( getColumns(), UNO_QUERY ); + Reference< css::beans::XPropertySet> column(columns->getByIndex( index ), UNO_QUERY ); + ::pq_sdbc_driver::alterColumnByDescriptor( + extractStringProperty( this, getStatics().SCHEMA_NAME ), + extractStringProperty( this, getStatics().NAME ), + m_pSettings, + m_conn->createStatement(), + column, + descriptor ); + m_pColumns->refresh(); +} + +Sequence<Type > Table::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XIndexesSupplier>::get(), + cppu::UnoType<css::sdbcx::XKeysSupplier>::get(), + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + cppu::UnoType<css::sdbcx::XRename>::get(), + cppu::UnoType<css::sdbcx::XAlterTable>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> Table::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any Table::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XIndexesSupplier * > ( this ), + static_cast< css::sdbcx::XKeysSupplier * > ( this ), + static_cast< css::sdbcx::XColumnsSupplier * > ( this ), + static_cast< css::sdbcx::XRename * > ( this ), + static_cast< css::sdbcx::XAlterTable * > ( this ) + ); + return ret; +} + +OUString Table::getName( ) +{ + Statics & st = getStatics(); + return concatQualified( + extractStringProperty( this, st.SCHEMA_NAME ), + extractStringProperty( this, st.NAME ) ); +} + +void Table::setName( const OUString& aName ) +{ + rename( aName ); +} + + +TableDescriptor::TableDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.tableDescriptor.implName, + getStatics().refl.tableDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.tableDescriptor.pProps ) +{ +} + +Reference< XNameAccess > TableDescriptor::getColumns( ) +{ + if( ! m_columns.is() ) + { + m_columns = new ColumnDescriptors(m_xMutex, m_conn, m_pSettings ); + } + return m_columns; +} + +Reference< XNameAccess > TableDescriptor::getIndexes() +{ + if( ! m_indexes.is() ) + { + m_indexes = ::pq_sdbc_driver::IndexDescriptors::create( + m_xMutex, + m_conn, + m_pSettings); + } + return m_indexes; +} + +Reference< XIndexAccess > TableDescriptor::getKeys( ) +{ + if( ! m_keys.is() ) + { + m_keys = ::pq_sdbc_driver::KeyDescriptors::create( + m_xMutex, + m_conn, + m_pSettings ); + } + return m_keys; +} + + +Sequence<Type > TableDescriptor::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XIndexesSupplier>::get(), + cppu::UnoType<css::sdbcx::XKeysSupplier>::get(), + cppu::UnoType<css::sdbcx::XColumnsSupplier>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> TableDescriptor::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any TableDescriptor::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XIndexesSupplier * > ( this ), + static_cast< css::sdbcx::XKeysSupplier * > ( this ), + static_cast< css::sdbcx::XColumnsSupplier * > ( this )); + return ret; +} + + +Reference< XPropertySet > TableDescriptor::createDataDescriptor( ) +{ + TableDescriptor * pTable = new TableDescriptor( + m_xMutex, m_conn, m_pSettings ); + + // TODO: deep copies + pTable->m_values = m_values; + + return Reference< XPropertySet > ( pTable ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xtable.hxx b/connectivity/source/drivers/postgresql/pq_xtable.hxx new file mode 100644 index 000000000..69e9d6435 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xtable.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XTABLE_HXX + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XIndexesSupplier.hpp> +#include <com/sun/star/sdbcx/XKeysSupplier.hpp> +#include <com/sun/star/sdbcx/XRename.hpp> +#include <com/sun/star/sdbcx/XAlterTable.hpp> +#include <com/sun/star/container/XNamed.hpp> + +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class Columns; + +class Table : public ReflectionBase, + public css::sdbcx::XColumnsSupplier, + public css::sdbcx::XIndexesSupplier, + public css::sdbcx::XKeysSupplier, + public css::sdbcx::XRename, + public css::sdbcx::XAlterTable +{ + css::uno::Reference< css::container::XNameAccess > m_columns; + css::uno::Reference< css::container::XIndexAccess > m_keys; + css::uno::Reference< css::container::XNameAccess > m_indexes; + Columns *m_pColumns; + +public: + Table( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + + // XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + + // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + + // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + + // XIndexesSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getIndexes( ) override; + + // XKeysSupplier + virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL + getKeys( ) override; + + // XRename + virtual void SAL_CALL rename( const OUString& newName ) override; + + // XAlterTable + virtual void SAL_CALL alterColumnByName( + const OUString& colName, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + virtual void SAL_CALL alterColumnByIndex( + sal_Int32 index, + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + // XNamed + virtual OUString SAL_CALL getName( ) override; + virtual void SAL_CALL setName( const OUString& aName ) override; +}; + + +class TableDescriptor + : public ReflectionBase, + public css::sdbcx::XColumnsSupplier, + public css::sdbcx::XIndexesSupplier, + public css::sdbcx::XKeysSupplier +{ + css::uno::Reference< css::container::XNameAccess > m_columns; + css::uno::Reference< css::container::XIndexAccess > m_keys; + css::uno::Reference< css::container::XNameAccess > m_indexes; + +public: + TableDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + +public: // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + +public: // XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getColumns( ) override; + +public: // XIndexesSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL + getIndexes( ) override; + +public: // XKeysSupplier + virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL + getKeys( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; +}; + + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xtables.cxx b/connectivity/source/drivers/postgresql/pq_xtables.cxx new file mode 100644 index 000000000..83758208b --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xtables.cxx @@ -0,0 +1,369 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbcx/Privilege.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xtables.hxx" +#include "pq_xviews.hxx" +#include "pq_xtable.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; + +using com::sun::star::container::XEnumerationAccess; +using com::sun::star::container::XEnumeration; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; +using com::sun::star::sdbc::XDatabaseMetaData; +using com::sun::star::sdbcx::XColumnsSupplier; +using com::sun::star::sdbcx::XKeysSupplier; + +namespace pq_sdbc_driver +{ +Tables::Tables( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, getStatics().TABLE ) +{} + +Tables::~Tables() +{} + +void Tables::refresh() +{ + try + { + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Reference< XDatabaseMetaData > meta = m_origin->getMetaData(); + + Reference< XResultSet > rs = + meta->getTables( Any(), st.cPERCENT,st.cPERCENT, Sequence< OUString > () ); + + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + + m_values.clear(); + sal_Int32 tableIndex = 0; + while( rs->next() ) + { + // if creating all these tables turns out to have too bad performance, we might + // instead offer a factory interface + Table * pTable = + new Table( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pTable; + + OUString name = xRow->getString( TABLE_INDEX_NAME+1); + OUString schema = xRow->getString( TABLE_INDEX_SCHEMA+1); + pTable->setPropertyValue_NoBroadcast_public( + st.CATALOG_NAME , makeAny(xRow->getString( TABLE_INDEX_CATALOG+1) ) ); + pTable->setPropertyValue_NoBroadcast_public( st.NAME , makeAny( name ) ); + pTable->setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME , makeAny( schema )); + pTable->setPropertyValue_NoBroadcast_public( + st.TYPE , makeAny( xRow->getString( TABLE_INDEX_TYPE+1) ) ); + pTable->setPropertyValue_NoBroadcast_public( + st.DESCRIPTION , makeAny( xRow->getString( TABLE_INDEX_REMARKS+1) ) ); + pTable->setPropertyValue_NoBroadcast_public( + st.PRIVILEGES , + makeAny( sal_Int32( css::sdbcx::Privilege::SELECT | + css::sdbcx::Privilege::INSERT | + css::sdbcx::Privilege::UPDATE | + css::sdbcx::Privilege::DELETE | + css::sdbcx::Privilege::READ | + css::sdbcx::Privilege::CREATE | + css::sdbcx::Privilege::ALTER | + css::sdbcx::Privilege::REFERENCE | + css::sdbcx::Privilege::DROP ) ) ); + + { + m_values.push_back( makeAny( prop ) ); + map[ schema + "." + name ] = tableIndex; + ++tableIndex; + } + } + m_name2index.swap( map ); + } + catch ( const css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +static void appendColumnList( + OUStringBuffer &buf, const Reference< XColumnsSupplier > & columnSupplier, ConnectionSettings *settings ) +{ + if( !columnSupplier.is() ) + return; + + Reference< XEnumerationAccess > columns( columnSupplier->getColumns(),UNO_QUERY ); + if( !columns.is() ) + return; + + Reference< XEnumeration > xEnum( columns->createEnumeration() ); + bool first = true; + Statics & st = getStatics(); + + while( xEnum.is() && xEnum->hasMoreElements() ) + { + if( first ) + { + first = false; + } + else + { + buf.append( ", " ); + } + Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY ); + OUString name = extractStringProperty( column, st.NAME ); + OUString defaultValue = extractStringProperty( column, st.DEFAULT_VALUE ); + bool isNullable = extractBoolProperty( column, st.IS_NULLABLE ); + bool isAutoIncrement = extractBoolProperty( column, st.IS_AUTO_INCREMENT ); + + bufferQuoteIdentifier( buf, name, settings ); + + OUString type = sqltype2string( column ); + if( isAutoIncrement ) + { + sal_Int32 dataType = 0; + column->getPropertyValue( st.TYPE ) >>= dataType; + if( css::sdbc::DataType::INTEGER == dataType ) + { + buf.append( " serial "); + isNullable = false; + } + else if( css::sdbc::DataType::BIGINT == dataType ) + { + buf.append( " serial8 " ); + isNullable = false; + } + else + buf.append( type ); + } + else + { + buf.append( type ); + } + if( !defaultValue.isEmpty() ) + { + bufferQuoteConstant( buf, defaultValue, settings ); + } + + if( ! isNullable ) + buf.append( " NOT NULL " ); + + } +} + +static void appendKeyList( + OUStringBuffer & buf, const Reference< XKeysSupplier > &keySupplier, ConnectionSettings *settings ) +{ + if( !keySupplier.is() ) + return; + + Reference< XEnumerationAccess > keys( keySupplier->getKeys(), UNO_QUERY ); + if(keys.is() ) + { + Reference< XEnumeration > xEnum = keys->createEnumeration(); + while( xEnum.is() && xEnum->hasMoreElements() ) + { + buf.append( ", " ); + Reference< XPropertySet > key( xEnum->nextElement(), UNO_QUERY ); + bufferKey2TableConstraint( buf, key, settings ); + } + } +} + +void Tables::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Reference< XStatement > stmt = + m_origin->createStatement(); + + Statics &st = getStatics(); + OUString name,schema; + descriptor->getPropertyValue( st.SCHEMA_NAME ) >>= schema; + descriptor->getPropertyValue( st.NAME ) >>= name; + + TransactionGuard transaction( stmt ); + + OUStringBuffer buf( 128 ); + buf.append( "CREATE TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schema, name , m_pSettings); + buf.append( "(" ); + + // columns + Reference< XColumnsSupplier > supplier( descriptor, UNO_QUERY ); + appendColumnList( buf, supplier, m_pSettings ); + + appendKeyList( buf, Reference< XKeysSupplier >( descriptor, UNO_QUERY ), m_pSettings ); + + buf.append( ") " ); + // execute the creation ! + transaction.executeUpdate( buf.makeStringAndClear() ); + + // description... + OUString description = extractStringProperty( descriptor, st.DESCRIPTION ); + if( !description.isEmpty() ) + { + buf.truncate(); + buf.append( "COMMENT ON TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schema, name, m_pSettings ); + buf.append( "IS " ); + bufferQuoteConstant( buf, description, m_pSettings); + + transaction.executeUpdate( buf.makeStringAndClear() ); + } + + // column descriptions + if( supplier.is() ) + { + Reference< XEnumerationAccess > columns( supplier->getColumns(),UNO_QUERY ); + if( columns.is() ) + { + Reference< XEnumeration > xEnum( columns->createEnumeration() ); + while( xEnum.is() && xEnum->hasMoreElements() ) + { + Reference< XPropertySet > column( xEnum->nextElement(), UNO_QUERY ); + description = extractStringProperty( column,st.DESCRIPTION ); + if( !description.isEmpty() ) + { + buf.truncate(); + buf.append( "COMMENT ON COLUMN " ); + bufferQuoteQualifiedIdentifier( + buf, schema, name, extractStringProperty( column, st.NAME ), m_pSettings ); + buf.append( "IS " ); + bufferQuoteConstant( buf, description, m_pSettings ); + transaction.executeUpdate( buf.makeStringAndClear() ); + } + } + } + } + + transaction.commit(); + + disposeNoThrow( stmt ); + // TODO: cheaper recalculate +// Container::append( concatQualified( schema, name ), descriptor ); // maintain the lists + refresh(); +} + +void Tables::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || index >= static_cast<sal_Int32>(m_values.size()) ) + { + throw css::lang::IndexOutOfBoundsException( + "TABLES: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + Statics &st = getStatics(); + OUString name,schema; + set->getPropertyValue( st.SCHEMA_NAME ) >>= schema; + set->getPropertyValue( st.NAME ) >>= name; + if( extractStringProperty( set, st.TYPE ) == st.VIEW && m_pSettings->views.is() ) + { + m_pSettings->pViewsImpl->dropByName( concatQualified( schema, name ) ); + } + else + { + OUStringBuffer update( 128 ); + update.append( "DROP " ); + if( extractStringProperty( set, st.TYPE ) == st.VIEW ) + update.append( "VIEW " ); + else + update.append( "TABLE " ); + bufferQuoteQualifiedIdentifier( update, schema, name, m_pSettings ); + Reference< XStatement > stmt = m_origin->createStatement( ); + DisposeGuard dispGuard( stmt ); + stmt->executeUpdate( update.makeStringAndClear() ); + } + + Container::dropByIndex( index ); +} + + +css::uno::Reference< css::beans::XPropertySet > Tables::createDataDescriptor() +{ + return new TableDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Tables::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + Tables **ppTables) +{ + *ppTables = new Tables( refMutex, origin, pSettings ); + Reference< css::container::XNameAccess > ret = *ppTables; + (*ppTables)->refresh(); + + return ret; +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xtables.hxx b/connectivity/source/drivers/postgresql/pq_xtables.hxx new file mode 100644 index 000000000..33eab3a5b --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xtables.hxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XTABLES_HXX + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +class Tables : public Container +{ + +public: // instances Tables 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + Tables ** ppTables); + +protected: + Tables( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + + virtual ~Tables() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop +// virtual void SAL_CALL dropByName( const OUString& elementName ) +// throw (css::sdbc::SQLException, +// css::container::NoSuchElementException, +// css::uno::RuntimeException); + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; + +protected: + using Container::disposing; +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xuser.cxx b/connectivity/source/drivers/postgresql/pq_xuser.cxx new file mode 100644 index 000000000..bc06c5410 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xuser.cxx @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <sal/log.hxx> +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +#include "pq_xuser.hxx" +#include "pq_tools.hxx" +#include "pq_statics.hxx" + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +User::User( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.user.implName, + getStatics().refl.user.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.user.pProps ) +{} + +Reference< XPropertySet > User::createDataDescriptor( ) +{ + UserDescriptor * pUser = new UserDescriptor( m_xMutex, m_conn, m_pSettings ); + pUser->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pUser ); +} + + +Sequence<Type > User::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XUser>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> User::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any User::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XUser * > ( this ) ); + return ret; +} + + +void User::changePassword( + const OUString&, const OUString& newPassword ) +{ + OUStringBuffer buf(128); + buf.append( "ALTER USER " ); + bufferQuoteIdentifier( buf, extractStringProperty( this, getStatics().NAME ), m_pSettings ); + buf.append( " PASSWORD " ); + bufferQuoteConstant( buf, newPassword, m_pSettings ); + Reference< XStatement > stmt = m_conn->createStatement(); + DisposeGuard guard( stmt ); + stmt->executeUpdate( buf.makeStringAndClear() ); +} + +sal_Int32 User::getPrivileges( const OUString& objName, sal_Int32 objType ) +{ + SAL_INFO("connectivity.postgresql", "User::getPrivileges[\"Name\"] got called for " << objName << "(type=" << objType << ")"); + // all privileges + return 0xffffffff; +} + +sal_Int32 User::getGrantablePrivileges( const OUString&, sal_Int32 ) +{ + // all privileges + return 0xffffffff; +} + +void User::grantPrivileges( const OUString&, sal_Int32, sal_Int32 ) +{ + throw css::sdbc::SQLException("pq_driver: privilege change not implemented yet", + *this, OUString(), 1, Any() ); +} + +void User::revokePrivileges( const OUString&, sal_Int32, sal_Int32 ) +{ + throw css::sdbc::SQLException("pq_driver: privilege change not implemented yet", + *this, OUString(), 1, Any() ); +} + + +UserDescriptor::UserDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings ) + : ReflectionBase( + getStatics().refl.userDescriptor.implName, + getStatics().refl.userDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.userDescriptor.pProps ) +{} + +Reference< XPropertySet > UserDescriptor::createDataDescriptor( ) +{ + UserDescriptor * pUser = new UserDescriptor( m_xMutex, m_conn, m_pSettings ); + pUser->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pUser ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xuser.hxx b/connectivity/source/drivers/postgresql/pq_xuser.hxx new file mode 100644 index 000000000..950cd998b --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xuser.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XUSER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XUSER_HXX + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XUser.hpp> + +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ + +class User : public ReflectionBase, + public css::sdbcx::XUser +{ + +public: + User( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + + // XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + + // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + + // XUser : XAuthorizable + virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + virtual void SAL_CALL changePassword( const OUString& oldPassword, const OUString& newPassword ) override; +}; + +class UserDescriptor : public ReflectionBase +{ +public: + UserDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; +}; + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xusers.cxx b/connectivity/source/drivers/postgresql/pq_xusers.cxx new file mode 100644 index 000000000..a6fe3489f --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xusers.cxx @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xusers.hxx" +#include "pq_xuser.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; + +using com::sun::star::container::NoSuchElementException; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; + +namespace pq_sdbc_driver +{ +Users::Users( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, getStatics().USER ) +{} + +Users::~Users() +{} + +void Users::refresh() +{ + try + { + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Reference< XStatement > stmt = m_origin->createStatement(); + + Reference< XResultSet > rs = stmt->executeQuery( "SELECT usename FROM pg_shadow" ); + + Reference< XRow > xRow( rs , UNO_QUERY ); + + String2IntMap map; + + m_values.clear(); + sal_Int32 tableIndex = 0; + while( rs->next() ) + { + User * pUser = + new User( m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pUser; + + OUString name = xRow->getString( 1); + pUser->setPropertyValue_NoBroadcast_public( + st.NAME , makeAny(xRow->getString( TABLE_INDEX_CATALOG+1) ) ); + + { + m_values.push_back( makeAny( prop ) ); + map[ name ] = tableIndex; + ++tableIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + + fire( RefreshedBroadcaster( *this ) ); +} + + +void Users::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + OUStringBuffer update( 128 ); + update.append( "CREATE USER " ); + bufferQuoteIdentifier( update, extractStringProperty( descriptor, getStatics().NAME ), m_pSettings ); + update.append( " PASSWORD " ); + bufferQuoteConstant( update, extractStringProperty( descriptor, getStatics().PASSWORD ), m_pSettings ); + + Reference< XStatement > stmt = m_origin->createStatement( ); + DisposeGuard disposeGuard( stmt ); + stmt->executeUpdate( update.makeStringAndClear() ); +} + +void Users::dropByName( const OUString& elementName ) +{ + String2IntMap::const_iterator ii = m_name2index.find( elementName ); + if( ii == m_name2index.end() ) + { + throw css::container::NoSuchElementException( + "User " + elementName + " is unknown, so it can't be dropped", + *this ); + } + dropByIndex( ii->second ); +} + +void Users::dropByIndex( sal_Int32 index ) +{ + + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || index >= static_cast<sal_Int32>(m_values.size()) ) + { + throw css::lang::IndexOutOfBoundsException( + "USERS: Index out of range (allowed 0 to " + + OUString::number( m_values.size() -1 ) + + ", got " + OUString::number( index ) + + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + OUString name; + set->getPropertyValue( getStatics().NAME ) >>= name; + + OUStringBuffer update( 128 ); + update.append( "DROP USER " ); + bufferQuoteIdentifier( update, name, m_pSettings ); + + Reference< XStatement > stmt = m_origin->createStatement( ); + DisposeGuard disposeGuard( stmt ); + stmt->executeUpdate( update.makeStringAndClear() ); +} + + +css::uno::Reference< css::beans::XPropertySet > Users::createDataDescriptor() +{ + return new UserDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Users::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) +{ + Users *pUsers = new Users( refMutex, origin, pSettings ); + Reference< css::container::XNameAccess > ret = pUsers; + pUsers->refresh(); + + return ret; +} + +void Users::disposing() +{ +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xusers.hxx b/connectivity/source/drivers/postgresql/pq_xusers.hxx new file mode 100644 index 000000000..359b97dd1 --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xusers.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XUSERS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XUSERS_HXX + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +class Users final : public Container +{ + +public: // instances Tables 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + +private: + Users( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ); + + virtual ~Users() override; + +public: + // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + // XDrop + virtual void SAL_CALL dropByName( const OUString& elementName ) override; + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + + // XRefreshable + virtual void SAL_CALL refresh( ) override; + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; + +private: + virtual void SAL_CALL disposing() override; +}; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xview.cxx b/connectivity/source/drivers/postgresql/pq_xview.cxx new file mode 100644 index 000000000..1b00b9b5d --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xview.cxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> + +#include "pq_xview.hxx" +#include "pq_xviews.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::Any; +using com::sun::star::uno::makeAny; +using com::sun::star::uno::Type; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::SQLException; + +namespace pq_sdbc_driver +{ + +View::View( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.view.implName, + getStatics().refl.view.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.view.pProps ) +{} + +Reference< XPropertySet > View::createDataDescriptor( ) +{ + ViewDescriptor * pView = new ViewDescriptor( + m_xMutex, m_conn, m_pSettings ); + pView->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pView ); +} + +void View::rename( const OUString& newName ) +{ + MutexGuard guard( m_xMutex->GetMutex() ); + + Statics & st = getStatics(); + + OUString oldName = extractStringProperty(this,st.NAME ); + OUString schema = extractStringProperty(this,st.SCHEMA_NAME ); + OUString fullOldName = concatQualified( schema, oldName ); + + OUString newTableName; + OUString newSchemaName; + // OOo2.0 passes schema + dot + new-table-name while + // OO1.1.x passes new Name without schema + // in case name contains a dot, it is interpreted as schema.tablename + if( newName.indexOf( '.' ) >= 0 ) + { + splitConcatenatedIdentifier( newName, &newSchemaName, &newTableName ); + } + else + { + newTableName = newName; + newSchemaName = schema; + } + OUString fullNewName = concatQualified( newSchemaName, newTableName ); + + if( schema != newSchemaName ) + { + try + { + OUStringBuffer buf(128); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier(buf, schema, oldName, m_pSettings ); + buf.append( "SET SCHEMA" ); + bufferQuoteIdentifier( buf, newSchemaName, m_pSettings ); + Reference< XStatement > statement = m_conn->createStatement(); + statement->executeUpdate( buf.makeStringAndClear() ); + setPropertyValue_NoBroadcast_public( st.SCHEMA_NAME, makeAny(newSchemaName) ); + disposeNoThrow( statement ); + schema = newSchemaName; + } + catch( css::sdbc::SQLException &e ) + { + OUString buf( e.Message + "(NOTE: Only postgresql server >= V8.1 support changing a table's schema)" ); + e.Message = buf; + throw; + } + + } + if( oldName != newTableName ) + { + OUStringBuffer buf(128); + buf.append( "ALTER TABLE" ); + bufferQuoteQualifiedIdentifier( buf, schema, oldName, m_pSettings ); + buf.append( "RENAME TO" ); + bufferQuoteIdentifier( buf, newTableName, m_pSettings ); + Reference< XStatement > statement = m_conn->createStatement(); + statement->executeUpdate( buf.makeStringAndClear() ); + setPropertyValue_NoBroadcast_public( st.NAME, makeAny(newTableName) ); + } + + // inform the container of the name change ! + if( m_pSettings->views.is() ) + { + m_pSettings->pViewsImpl->rename( fullOldName, fullNewName ); + } +} + +Sequence<Type > View::getTypes() +{ + static cppu::OTypeCollection collection( + cppu::UnoType<css::sdbcx::XRename>::get(), + ReflectionBase::getTypes()); + + return collection.getTypes(); +} + +Sequence< sal_Int8> View::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +Any View::queryInterface( const Type & reqType ) +{ + Any ret = ReflectionBase::queryInterface( reqType ); + if( ! ret.hasValue() ) + ret = ::cppu::queryInterface( + reqType, + static_cast< css::sdbcx::XRename * > ( this ) + ); + return ret; +} + +OUString View::getName( ) +{ + Statics & st = getStatics(); + return concatQualified( + extractStringProperty( this, st.SCHEMA_NAME ), + extractStringProperty( this, st.NAME ) ); +} + +void View::setName( const OUString& aName ) +{ + rename( aName ); +} + + +ViewDescriptor::ViewDescriptor( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings) + : ReflectionBase( + getStatics().refl.viewDescriptor.implName, + getStatics().refl.viewDescriptor.serviceNames, + refMutex, + connection, + pSettings, + * getStatics().refl.viewDescriptor.pProps ) +{} + +Reference< XPropertySet > ViewDescriptor::createDataDescriptor( ) +{ + ViewDescriptor * pView = new ViewDescriptor( + m_xMutex, m_conn, m_pSettings ); + pView->copyValuesFrom( this ); + + return Reference< XPropertySet > ( pView ); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xview.hxx b/connectivity/source/drivers/postgresql/pq_xview.hxx new file mode 100644 index 000000000..d5c86981f --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xview.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XVIEW_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XVIEW_HXX + +#include <cppuhelper/component.hxx> +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XRename.hpp> +#include <com/sun/star/container/XNamed.hpp> + +#include "pq_xbase.hxx" + +namespace pq_sdbc_driver +{ +class View : public ReflectionBase, + public css::sdbcx::XRename +{ +public: + View( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + + // XInterface + virtual void SAL_CALL acquire() throw() override { ReflectionBase::acquire(); } + virtual void SAL_CALL release() throw() override { ReflectionBase::release(); } + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type & reqType ) override; + + // XTypeProvider, first implemented by OPropertySetHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8> SAL_CALL getImplementationId() override; + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; + + // XRename + virtual void SAL_CALL rename( const OUString& newName ) override; + + // XNamed + virtual OUString SAL_CALL getName( ) override; + virtual void SAL_CALL setName( const OUString& aName ) override; + +}; + + +class ViewDescriptor : public ReflectionBase +{ +public: + ViewDescriptor( const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & connection, + ConnectionSettings *pSettings); + + // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL + createDataDescriptor( ) override; +}; + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xviews.cxx b/connectivity/source/drivers/postgresql/pq_xviews.cxx new file mode 100644 index 000000000..ac684a16c --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xviews.cxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <cppuhelper/exc_hlp.hxx> + +#include "pq_xviews.hxx" +#include "pq_xview.hxx" +#include "pq_xtables.hxx" +#include "pq_statics.hxx" +#include "pq_tools.hxx" + +using osl::MutexGuard; + +using com::sun::star::beans::XPropertySet; + +using com::sun::star::uno::makeAny; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::Reference; + +using com::sun::star::container::NoSuchElementException; + +using com::sun::star::sdbc::XRow; +using com::sun::star::sdbc::XStatement; +using com::sun::star::sdbc::XResultSet; + + +namespace pq_sdbc_driver +{ +Views::Views( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings ) + : Container( refMutex, origin, pSettings, getStatics().VIEW ) +{} + +Views::~Views() +{} + +void Views::refresh() +{ + try + { + osl::MutexGuard guard( m_xMutex->GetMutex() ); + Statics & st = getStatics(); + + Reference< XStatement > stmt = m_origin->createStatement(); + + Reference< XResultSet > rs = stmt->executeQuery("SELECT " + "DISTINCT ON( pg_namespace.nspname, relname) " // needed because of duplicates + "pg_namespace.nspname," // 1 + "relname," // 2 + "pg_get_viewdef(ev_class) " // 3 + "FROM pg_namespace, pg_class, pg_rewrite " + "WHERE pg_namespace.oid = relnamespace " + "AND pg_class.oid = ev_class " + "AND relkind=\'v\'" ); + + Reference< XRow > xRow( rs , UNO_QUERY ); + + m_values.clear(); + String2IntMap map; + sal_Int32 viewIndex = 0; + + while( rs->next() ) + { + OUString table, schema, command; + schema = xRow->getString( 1 ); + table = xRow->getString( 2 ); + command = xRow->getString( 3 ); + + View *pView = new View (m_xMutex, m_origin, m_pSettings ); + Reference< css::beans::XPropertySet > prop = pView; + + pView->setPropertyValue_NoBroadcast_public(st.NAME , makeAny(table) ); + pView->setPropertyValue_NoBroadcast_public(st.SCHEMA_NAME, makeAny(schema) ); + pView->setPropertyValue_NoBroadcast_public(st.COMMAND, makeAny(command) ); + + { + m_values.push_back( makeAny( prop ) ); + map[ schema + "." + table ] = viewIndex; + ++viewIndex; + } + } + m_name2index.swap( map ); + } + catch ( css::sdbc::SQLException & e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( e.Message, + e.Context, anyEx ); + } + fire( RefreshedBroadcaster( *this ) ); +} + + +void Views::appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + + Statics &st = getStatics(); + OUString name,schema,command; + descriptor->getPropertyValue( st.SCHEMA_NAME ) >>= schema; + descriptor->getPropertyValue( st.NAME ) >>= name; + descriptor->getPropertyValue( st.COMMAND ) >>= command; + + Reference< XStatement > stmt = m_origin->createStatement(); + + OUStringBuffer buf( 128 ); + + buf.append( "CREATE VIEW "); + bufferQuoteQualifiedIdentifier( buf, schema, name, m_pSettings ); + buf.append(" AS " ).append( command ); + + stmt->executeUpdate( buf.makeStringAndClear() ); + + disposeNoThrow( stmt ); + refresh(); + if( m_pSettings->tables.is() ) + { + m_pSettings->pTablesImpl->refresh(); + } +} + +void Views::dropByName( const OUString& elementName ) +{ + String2IntMap::const_iterator ii = m_name2index.find( elementName ); + if( ii == m_name2index.end() ) + { + throw css::container::NoSuchElementException( + "View " + elementName + " is unknown, so it can't be dropped", *this ); + } + dropByIndex( ii->second ); +} + +void Views::dropByIndex( sal_Int32 index ) +{ + osl::MutexGuard guard( m_xMutex->GetMutex() ); + if( index < 0 || index >= static_cast<sal_Int32>(m_values.size()) ) + { + throw css::lang::IndexOutOfBoundsException( + "VIEWS: Index out of range (allowed 0 to " + OUString::number(m_values.size() -1) + + ", got " + OUString::number( index ) + ")", + *this ); + } + + Reference< XPropertySet > set; + m_values[index] >>= set; + Statics &st = getStatics(); + OUString name,schema; + set->getPropertyValue( st.SCHEMA_NAME ) >>= schema; + set->getPropertyValue( st.NAME ) >>= name; + + Reference< XStatement > stmt = m_origin->createStatement( ); + + stmt->executeUpdate( "DROP VIEW \"" + schema + "\".\"" + name + "\"" ); +} + + +css::uno::Reference< css::beans::XPropertySet > Views::createDataDescriptor() +{ + return new ViewDescriptor( m_xMutex, m_origin, m_pSettings ); +} + +Reference< css::container::XNameAccess > Views::create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + Views **ppViews) +{ + *ppViews = new Views( refMutex, origin, pSettings ); + Reference< css::container::XNameAccess > ret = *ppViews; + (*ppViews)->refresh(); + + return ret; +} + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/postgresql/pq_xviews.hxx b/connectivity/source/drivers/postgresql/pq_xviews.hxx new file mode 100644 index 000000000..5ce5b879b --- /dev/null +++ b/connectivity/source/drivers/postgresql/pq_xviews.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * Effective License of whole file: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Parts "Copyright by Sun Microsystems, Inc" prior to August 2011: + * + * The Contents of this file are made available subject to the terms of + * the GNU Lesser General Public License Version 2.1 + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * Contributor(s): Joerg Budischewski + * + * All parts contributed on or after August 2011: + * + * 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/. + * + ************************************************************************/ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XVIEWS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_POSTGRESQL_PQ_XVIEWS_HXX + +#include "pq_xcontainer.hxx" + +namespace pq_sdbc_driver +{ + +class Views : public Container +{ + +public: // instances Views 'exception safe' + static css::uno::Reference< css::container::XNameAccess > create( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings, + Views **ppViews ); + +protected: + Views( + const ::rtl::Reference< comphelper::RefCountedMutex > & refMutex, + const css::uno::Reference< css::sdbc::XConnection > & origin, + ConnectionSettings *pSettings); + + virtual ~Views() override; + +public: // XAppend + virtual void SAL_CALL appendByDescriptor( + const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + +public: // XDrop + virtual void SAL_CALL dropByName( const OUString& elementName ) override; + virtual void SAL_CALL dropByIndex( sal_Int32 index ) override; + +public: // XRefreshable + virtual void SAL_CALL refresh( ) override; + +public: // XDataDescriptorFactory + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override; + +protected: + using Container::disposing; + +}; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/writer/WCatalog.cxx b/connectivity/source/drivers/writer/WCatalog.cxx new file mode 100644 index 000000000..8671af7bd --- /dev/null +++ b/connectivity/source/drivers/writer/WCatalog.cxx @@ -0,0 +1,60 @@ +/* -*- 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 <writer/WCatalog.hxx> +#include <writer/WTables.hxx> + +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> + +#include <connectivity/sdbcx/VCollection.hxx> + +#include <writer/WConnection.hxx> + +using namespace ::com::sun::star; + +namespace connectivity::writer +{ +OWriterCatalog::OWriterCatalog(OWriterConnection* pConnection) + : file::OFileCatalog(pConnection) +{ +} + +void OWriterCatalog::refreshTables() +{ + ::std::vector<OUString> aVector; + uno::Sequence<OUString> aTypes; + OWriterConnection::ODocHolder aDocHolder(static_cast<OWriterConnection*>(m_pConnection)); + uno::Reference<sdbc::XResultSet> xResult = m_xMetaData->getTables(uno::Any(), "%", "%", aTypes); + + if (xResult.is()) + { + uno::Reference<sdbc::XRow> xRow(xResult, uno::UNO_QUERY); + while (xResult->next()) + aVector.push_back(xRow->getString(3)); + } + if (m_pTables) + m_pTables->reFill(aVector); + else + m_pTables = std::make_unique<OWriterTables>(m_xMetaData, *this, m_aMutex, aVector); +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/writer/WConnection.cxx b/connectivity/source/drivers/writer/WConnection.cxx new file mode 100644 index 000000000..c4cc699e4 --- /dev/null +++ b/connectivity/source/drivers/writer/WConnection.cxx @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <writer/WConnection.hxx> +#include <writer/WDatabaseMetaData.hxx> +#include <writer/WCatalog.hxx> +#include <writer/WDriver.hxx> +#include <resource/sharedresources.hxx> +#include <strings.hrc> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <tools/urlobj.hxx> +#include <sal/log.hxx> +#include <component/CPreparedStatement.hxx> +#include <component/CStatement.hxx> +#include <unotools/pathoptions.hxx> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::com::sun::star; + +using OConnection_BASE = connectivity::file::OConnection; + +namespace connectivity::writer +{ +OWriterConnection::OWriterConnection(ODriver* _pDriver) + : OConnection(_pDriver) + , m_nDocCount(0) +{ +} + +OWriterConnection::~OWriterConnection() = default; + +void OWriterConnection::construct(const OUString& rURL, + const uno::Sequence<beans::PropertyValue>& rInfo) +{ + // open file + + sal_Int32 nLen = rURL.indexOf(':'); + nLen = rURL.indexOf(':', nLen + 1); + OUString aDSN(rURL.copy(nLen + 1)); + + m_aFileName = aDSN; + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + { + SvtPathOptions aPathOptions; + m_aFileName = aPathOptions.SubstituteVariable(m_aFileName); + } + aURL.SetSmartURL(m_aFileName); + if (aURL.GetProtocol() == INetProtocol::NotValid) + { + // don't pass invalid URL to loadComponentFromURL + throw sdbc::SQLException(); + } + m_aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + + m_sPassword.clear(); + const char pPwd[] = "password"; + + const beans::PropertyValue* pIter = rInfo.getConstArray(); + const beans::PropertyValue* pEnd = pIter + rInfo.getLength(); + for (; pIter != pEnd; ++pIter) + { + if (pIter->Name == pPwd) + { + pIter->Value >>= m_sPassword; + break; + } + } // for(;pIter != pEnd;++pIter) + ODocHolder aDocHolder(this); // just to test that the doc can be loaded + acquireDoc(); +} + +uno::Reference<text::XTextDocument> const& OWriterConnection::acquireDoc() +{ + if (m_xDoc.is()) + { + osl_atomic_increment(&m_nDocCount); + return m_xDoc; + } + // open read-only as long as updating isn't implemented + uno::Sequence<beans::PropertyValue> aArgs(2); + aArgs[0].Name = "Hidden"; + aArgs[0].Value <<= true; + aArgs[1].Name = "ReadOnly"; + aArgs[1].Value <<= true; + + if (!m_sPassword.isEmpty()) + { + const sal_Int32 nPos = aArgs.getLength(); + aArgs.realloc(nPos + 1); + aArgs[nPos].Name = "Password"; + aArgs[nPos].Value <<= m_sPassword; + } + + uno::Reference<frame::XDesktop2> xDesktop + = frame::Desktop::create(getDriver()->getComponentContext()); + uno::Reference<lang::XComponent> xComponent; + uno::Any aLoaderException; + try + { + xComponent = xDesktop->loadComponentFromURL(m_aFileName, "_blank", 0, aArgs); + } + catch (const uno::Exception&) + { + aLoaderException = ::cppu::getCaughtException(); + } + + m_xDoc.set(xComponent, uno::UNO_QUERY); + + // if the URL is not a text document, throw the exception here + // instead of at the first access to it + if (!m_xDoc.is()) + { + if (aLoaderException.hasValue()) + { + uno::Exception aLoaderError; + OSL_VERIFY(aLoaderException >>= aLoaderError); + + SAL_WARN("connectivity.writer", + "empty m_xDoc, " << exceptionToString(aLoaderException)); + } + + const OUString sError(m_aResources.getResourceStringWithSubstitution( + STR_COULD_NOT_LOAD_FILE, "$filename$", m_aFileName)); + ::dbtools::throwGenericSQLException(sError, *this); + } + osl_atomic_increment(&m_nDocCount); + m_xCloseVetoButTerminateListener.set(new CloseVetoButTerminateListener); + m_xCloseVetoButTerminateListener->start(m_xDoc, xDesktop); + return m_xDoc; +} + +void OWriterConnection::releaseDoc() +{ + if (osl_atomic_decrement(&m_nDocCount) == 0) + { + if (m_xCloseVetoButTerminateListener.is()) + { + m_xCloseVetoButTerminateListener->stop(); // dispose m_xDoc + m_xCloseVetoButTerminateListener.clear(); + } + m_xDoc.clear(); + } +} + +void OWriterConnection::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + m_nDocCount = 0; + if (m_xCloseVetoButTerminateListener.is()) + { + m_xCloseVetoButTerminateListener->stop(); // dispose m_xDoc + m_xCloseVetoButTerminateListener.clear(); + } + m_xDoc.clear(); + + OConnection::disposing(); +} + +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OWriterConnection, "com.sun.star.sdbc.drivers.writer.Connection", + "com.sun.star.sdbc.Connection") + +uno::Reference<sdbc::XDatabaseMetaData> SAL_CALL OWriterConnection::getMetaData() +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + uno::Reference<sdbc::XDatabaseMetaData> xMetaData = m_xMetaData; + if (!xMetaData.is()) + { + xMetaData = new OWriterDatabaseMetaData(this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +css::uno::Reference<css::sdbcx::XTablesSupplier> OWriterConnection::createCatalog() +{ + ::osl::MutexGuard aGuard(m_aMutex); + uno::Reference<css::sdbcx::XTablesSupplier> xTab = m_xCatalog; + if (!xTab.is()) + { + auto pCat = new OWriterCatalog(this); + xTab = pCat; + m_xCatalog = xTab; + } + return xTab; +} + +uno::Reference<sdbc::XStatement> SAL_CALL OWriterConnection::createStatement() +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + uno::Reference<sdbc::XStatement> xReturn = new component::OComponentStatement(this); + m_aStatements.push_back(uno::WeakReferenceHelper(xReturn)); + return xReturn; +} + +uno::Reference<sdbc::XPreparedStatement> + SAL_CALL OWriterConnection::prepareStatement(const OUString& sql) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + auto pStmt = new component::OComponentPreparedStatement(this); + uno::Reference<sdbc::XPreparedStatement> xHoldAlive = pStmt; + pStmt->construct(sql); + m_aStatements.push_back(uno::WeakReferenceHelper(*pStmt)); + return pStmt; +} + +uno::Reference<sdbc::XPreparedStatement> + SAL_CALL OWriterConnection::prepareCall(const OUString& /*sql*/) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OConnection_BASE::rBHelper.bDisposed); + + ::dbtools::throwFeatureNotImplementedSQLException("XConnection::prepareCall", *this); + return nullptr; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/writer/WDatabaseMetaData.cxx b/connectivity/source/drivers/writer/WDatabaseMetaData.cxx new file mode 100644 index 000000000..2e55a46d2 --- /dev/null +++ b/connectivity/source/drivers/writer/WDatabaseMetaData.cxx @@ -0,0 +1,112 @@ +/* -*- 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 <writer/WDatabaseMetaData.hxx> +#include <writer/WConnection.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XTextTablesSupplier.hpp> + +using namespace ::com::sun::star; + +namespace connectivity::writer +{ +OWriterDatabaseMetaData::OWriterDatabaseMetaData(file::OConnection* pConnection) + : OComponentDatabaseMetaData(pConnection) +{ +} + +OWriterDatabaseMetaData::~OWriterDatabaseMetaData() = default; + +OUString SAL_CALL OWriterDatabaseMetaData::getURL() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + return "sdbc:writer:" + m_pConnection->getURL(); +} + +uno::Reference<sdbc::XResultSet> SAL_CALL OWriterDatabaseMetaData::getTables( + const uno::Any& /*catalog*/, const OUString& /*schemaPattern*/, + const OUString& tableNamePattern, const uno::Sequence<OUString>& types) +{ + ::osl::MutexGuard aGuard(m_aMutex); + + auto pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTables); + uno::Reference<sdbc::XResultSet> xRef = pResult; + + // check if ORowSetValue type is given + // when no types are given then we have to return all tables e.g. TABLE + + OUString aTable("TABLE"); + + bool bTableFound = true; + sal_Int32 nLength = types.getLength(); + if (nLength) + { + bTableFound = false; + + const OUString* pIter = types.getConstArray(); + const OUString* pEnd = pIter + nLength; + for (; pIter != pEnd; ++pIter) + { + if (*pIter == aTable) + { + bTableFound = true; + break; + } + } + } + if (!bTableFound) + return xRef; + + // get the table names from the document + + OWriterConnection::ODocHolder aDocHolder(static_cast<OWriterConnection*>(m_pConnection)); + uno::Reference<text::XTextTablesSupplier> xDoc(aDocHolder.getDoc(), uno::UNO_QUERY); + if (!xDoc.is()) + throw sdbc::SQLException(); + uno::Reference<container::XNameAccess> xTables = xDoc->getTextTables(); + if (!xTables.is()) + throw sdbc::SQLException(); + uno::Sequence<OUString> aTableNames = xTables->getElementNames(); + + ODatabaseMetaDataResultSet::ORows aRows; + sal_Int32 nTableCount = aTableNames.getLength(); + for (sal_Int32 nTable = 0; nTable < nTableCount; nTable++) + { + OUString aName = aTableNames[nTable]; + if (match(tableNamePattern, aName, '\0')) + { + ODatabaseMetaDataResultSet::ORow aRow{ nullptr, nullptr, nullptr }; + aRow.reserve(6); + aRow.push_back(new ORowSetValueDecorator(aName)); + aRow.push_back(new ORowSetValueDecorator(aTable)); + aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue()); + aRows.push_back(aRow); + } + } + + pResult->setRows(aRows); + + return xRef; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/writer/WDriver.cxx b/connectivity/source/drivers/writer/WDriver.cxx new file mode 100644 index 000000000..63dc1f3f4 --- /dev/null +++ b/connectivity/source/drivers/writer/WDriver.cxx @@ -0,0 +1,80 @@ +/* -*- 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 <writer/WDriver.hxx> +#include <writer/WConnection.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <connectivity/dbexception.hxx> +#include <resource/sharedresources.hxx> +#include <strings.hrc> +#include <comphelper/processfactory.hxx> + +using namespace connectivity::file; +using namespace ::com::sun::star; + +namespace connectivity::writer +{ +OUString ODriver::getImplementationName_Static() { return "com.sun.star.comp.sdbc.writer.ODriver"; } + +OUString SAL_CALL ODriver::getImplementationName() { return getImplementationName_Static(); } + +uno::Reference<css::uno::XInterface> +ODriver_CreateInstance(const uno::Reference<lang::XMultiServiceFactory>& _rxFactory) +{ + return *(new ODriver(comphelper::getComponentContext(_rxFactory))); +} + +uno::Reference<sdbc::XConnection> + SAL_CALL ODriver::connect(const OUString& url, const uno::Sequence<beans::PropertyValue>& info) +{ + ::osl::MutexGuard aGuard(m_aMutex); + if (ODriver_BASE::rBHelper.bDisposed) + throw lang::DisposedException(); + + if (!acceptsURL(url)) + return nullptr; + + auto pCon = new OWriterConnection(this); + pCon->construct(url, info); + uno::Reference<sdbc::XConnection> xCon = pCon; + m_xConnections.push_back(uno::WeakReferenceHelper(*pCon)); + + return xCon; +} + +sal_Bool SAL_CALL ODriver::acceptsURL(const OUString& url) +{ + return url.startsWith("sdbc:writer:"); +} + +uno::Sequence<sdbc::DriverPropertyInfo> SAL_CALL +ODriver::getPropertyInfo(const OUString& url, const uno::Sequence<beans::PropertyValue>& /*info*/) +{ + if (!acceptsURL(url)) + { + SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage, *this); + } + return uno::Sequence<sdbc::DriverPropertyInfo>(); +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/writer/WTable.cxx b/connectivity/source/drivers/writer/WTable.cxx new file mode 100644 index 000000000..7236df247 --- /dev/null +++ b/connectivity/source/drivers/writer/WTable.cxx @@ -0,0 +1,253 @@ +/* -*- 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 <writer/WTable.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/text/XTextTablesSupplier.hpp> +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <writer/WConnection.hxx> +#include <connectivity/sdbcx/VColumn.hxx> +#include <sal/log.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/typeprovider.hxx> + +namespace com::sun::star::text +{ +class XTextDocument; +} + +using namespace ::com::sun::star; + +static void lcl_GetDataArea(const uno::Reference<text::XTextTable>& xTable, sal_Int32& rColumnCount, + sal_Int32& rRowCount) +{ + uno::Reference<container::XIndexAccess> xColumns = xTable->getColumns(); + if (xColumns.is()) + rColumnCount = xColumns->getCount(); + + uno::Reference<container::XIndexAccess> xRows = xTable->getRows(); + if (xRows.is()) + rRowCount = xRows->getCount() - 1; // first row (headers) is not counted +} + +static void lcl_GetColumnInfo(const uno::Reference<text::XTextTable>& xTable, sal_Int32 nDocColumn, + bool bHasHeaders, OUString& rName, sal_Int32& rDataType, + bool& rCurrency) +{ + uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY); + // get column name from first row, if range contains headers + if (bHasHeaders) + { + uno::Reference<text::XText> xHeaderText( + xCellRange->getCellByPosition(nDocColumn, /*nStartRow*/ 0), uno::UNO_QUERY); + if (xHeaderText.is()) + rName = xHeaderText->getString(); + } + + rCurrency = false; + rDataType = sdbc::DataType::VARCHAR; +} + +static void lcl_SetValue(connectivity::ORowSetValue& rValue, + const uno::Reference<text::XTextTable>& xTable, sal_Int32 nStartCol, + bool bHasHeaders, sal_Int32 nDBRow, sal_Int32 nDBColumn) +{ + sal_Int32 nDocColumn = nStartCol + nDBColumn - 1; // database counts from 1 + sal_Int32 nDocRow = nDBRow - 1; + if (bHasHeaders) + ++nDocRow; + + uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY); + uno::Reference<table::XCell> xCell; + try + { + xCell = xCellRange->getCellByPosition(nDocColumn, nDocRow); + } + catch (const lang::IndexOutOfBoundsException& /*rException*/) + { + SAL_WARN("connectivity.writer", + "getCellByPosition(" << nDocColumn << ", " << nDocRow << ") failed"); + rValue = OUString(); + } + + if (xCell.is()) + { + const uno::Reference<text::XText> xText(xCell, uno::UNO_QUERY); + if (xText.is()) + rValue = xText->getString(); + } +} + +namespace connectivity::writer +{ +void OWriterTable::fillColumns() +{ + if (!m_xTable.is()) + throw sdbc::SQLException(); + + OUString aTypeName; + ::comphelper::UStringMixEqual aCase( + m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()); + const bool bStoresMixedCaseQuotedIdentifiers + = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(); + + for (sal_Int32 i = 0; i < m_nDataCols; i++) + { + OUString aColumnName; + sal_Int32 eType = sdbc::DataType::OTHER; + bool bCurrency = false; + + lcl_GetColumnInfo(m_xTable, m_nStartCol + i, m_bHasHeaders, aColumnName, eType, bCurrency); + + sal_Int32 nPrecision = 0; //! ... + sal_Int32 nDecimals = 0; //! ... + + switch (eType) + { + case sdbc::DataType::VARCHAR: + aTypeName = "VARCHAR"; + break; + case sdbc::DataType::DECIMAL: + aTypeName = "DECIMAL"; + break; + case sdbc::DataType::BIT: + aTypeName = "BOOL"; + break; + case sdbc::DataType::DATE: + aTypeName = "DATE"; + break; + case sdbc::DataType::TIME: + aTypeName = "TIME"; + break; + case sdbc::DataType::TIMESTAMP: + aTypeName = "TIMESTAMP"; + break; + default: + SAL_WARN("connectivity.writer", "missing type name"); + aTypeName.clear(); + } + + // check if the column name already exists + OUString aAlias = aColumnName; + auto aFind = connectivity::find(m_aColumns->begin(), m_aColumns->end(), aAlias, aCase); + sal_Int32 nExprCnt = 0; + while (aFind != m_aColumns->end()) + { + aAlias = aColumnName + OUString::number(++nExprCnt); + aFind = connectivity::find(m_aColumns->begin(), m_aColumns->end(), aAlias, aCase); + } + + auto pColumn = new sdbcx::OColumn( + aAlias, aTypeName, OUString(), OUString(), sdbc::ColumnValue::NULLABLE, nPrecision, + nDecimals, eType, false, false, bCurrency, bStoresMixedCaseQuotedIdentifiers, + m_CatalogName, getSchema(), getName()); + uno::Reference<XPropertySet> xCol = pColumn; + m_aColumns->push_back(xCol); + } +} + +OWriterTable::OWriterTable(sdbcx::OCollection* _pTables, OWriterConnection* _pConnection, + const OUString& Name, const OUString& Type) + : OWriterTable_BASE(_pTables, _pConnection, Name, Type, OUString() /*Description*/, + OUString() /*SchemaName*/, OUString() /*CatalogName*/) + , m_pWriterConnection(_pConnection) + , m_nStartCol(0) + , m_nDataCols(0) + , m_bHasHeaders(false) +{ +} + +void OWriterTable::construct() +{ + uno::Reference<text::XTextDocument> xDoc = m_pWriterConnection->acquireDoc(); + if (xDoc.is()) + { + uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(xDoc, uno::UNO_QUERY); + uno::Reference<container::XNameAccess> xTables = xTextTablesSupplier->getTextTables(); + if (xTables.is() && xTables->hasByName(m_Name)) + { + m_xTable.set(xTables->getByName(m_Name), uno::UNO_QUERY); + if (m_xTable.is()) + { + lcl_GetDataArea(m_xTable, m_nDataCols, m_nDataRows); + m_bHasHeaders = true; + } + } + } + + fillColumns(); + + refreshColumns(); +} + +void SAL_CALL OWriterTable::disposing() +{ + OFileTable::disposing(); + ::osl::MutexGuard aGuard(m_aMutex); + m_aColumns = nullptr; + if (m_pWriterConnection) + m_pWriterConnection->releaseDoc(); + m_pWriterConnection = nullptr; +} + +uno::Sequence<sal_Int8> OWriterTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +sal_Int64 OWriterTable::getSomething(const uno::Sequence<sal_Int8>& rId) +{ + return (isUnoTunnelId<OWriterTable>(rId)) ? reinterpret_cast<sal_Int64>(this) + : OWriterTable_BASE::getSomething(rId); +} + +bool OWriterTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) +{ + // read the bookmark + + _rRow->setDeleted(false); + *(*_rRow)[0] = m_nFilePos; + + if (!bRetrieveData) + return true; + + // fields + + const OValueRefVector::size_type nCount = std::min(_rRow->size(), _rCols.size() + 1); + for (OValueRefVector::size_type i = 1; i < nCount; i++) + { + if ((*_rRow)[i]->isBound()) + { + lcl_SetValue((*_rRow)[i]->get(), m_xTable, m_nStartCol, m_bHasHeaders, m_nFilePos, i); + } + } + return true; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/writer/WTables.cxx b/connectivity/source/drivers/writer/WTables.cxx new file mode 100644 index 000000000..15dc9e0c1 --- /dev/null +++ b/connectivity/source/drivers/writer/WTables.cxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <writer/WTables.hxx> + +#include <sal/config.h> + +#include <writer/WConnection.hxx> +#include <file/FCatalog.hxx> +#include <writer/WTable.hxx> + +using namespace ::com::sun::star; + +namespace connectivity::writer +{ +sdbcx::ObjectType OWriterTables::createObject(const OUString& rName) +{ + auto pTable = new OWriterTable(this, + static_cast<OWriterConnection*>( + static_cast<file::OFileCatalog&>(m_rParent).getConnection()), + rName, "TABLE"); + sdbcx::ObjectType xRet = pTable; + pTable->construct(); + return xRet; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/writer/Wservices.cxx b/connectivity/source/drivers/writer/Wservices.cxx new file mode 100644 index 000000000..7f997d7d1 --- /dev/null +++ b/connectivity/source/drivers/writer/Wservices.cxx @@ -0,0 +1,90 @@ +/* -*- 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 <writer/WDriver.hxx> +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace com::sun::star; + +using createFactoryFunc = uno::Reference<lang::XSingleServiceFactory> (*)( + const uno::Reference<lang::XMultiServiceFactory>& rServiceManager, + const OUString& rComponentName, ::cppu::ComponentInstantiation pCreateFunction, + const uno::Sequence<OUString>& rServiceNames, rtl_ModuleCount*); + +namespace +{ +struct ProviderRequest +{ +private: + uno::Reference<lang::XSingleServiceFactory> xRet; + uno::Reference<lang::XMultiServiceFactory> const xServiceManager; + OUString const sImplementationName; + +public: + ProviderRequest(void* pServiceManager, char const* pImplementationName) + : xServiceManager(static_cast<lang::XMultiServiceFactory*>(pServiceManager)) + , sImplementationName(OUString::createFromAscii(pImplementationName)) + { + } + + bool CREATE_PROVIDER(const OUString& Implname, const uno::Sequence<OUString>& Services, + ::cppu::ComponentInstantiation Factory, createFactoryFunc creator) + { + if (!xRet.is() && (Implname == sImplementationName)) + { + try + { + xRet = creator(xServiceManager, sImplementationName, Factory, Services, nullptr); + } + catch (...) + { + } + } + return xRet.is(); + } + + uno::XInterface* getProvider() const { return xRet.get(); } +}; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* +connectivity_writer_component_getFactory(const char* pImplementationName, void* pServiceManager, + void* /*pRegistryKey*/) +{ + void* pRet = nullptr; + if (pServiceManager) + { + ProviderRequest aReq(pServiceManager, pImplementationName); + + aReq.CREATE_PROVIDER(connectivity::writer::ODriver::getImplementationName_Static(), + connectivity::writer::ODriver::getSupportedServiceNames_Static(), + connectivity::writer::ODriver_CreateInstance, + ::cppu::createSingleFactory); + + if (aReq.getProvider()) + aReq.getProvider()->acquire(); + + pRet = aReq.getProvider(); + } + + return pRet; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/writer/writer.component b/connectivity/source/drivers/writer/writer.component new file mode 100644 index 000000000..3bf9d6e79 --- /dev/null +++ b/connectivity/source/drivers/writer/writer.component @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="connectivity_writer" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.writer.ODriver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> diff --git a/connectivity/source/inc/AutoRetrievingBase.hxx b/connectivity/source/inc/AutoRetrievingBase.hxx new file mode 100644 index 000000000..f24d94f79 --- /dev/null +++ b/connectivity/source/inc/AutoRetrievingBase.hxx @@ -0,0 +1,51 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_AUTORETRIEVINGBASE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_AUTORETRIEVINGBASE_HXX + +#include <rtl/ustring.hxx> +#include <connectivity/dbtoolsdllapi.hxx> + +namespace connectivity +{ + class OOO_DLLPUBLIC_DBTOOLS OAutoRetrievingBase + { + OUString m_sGeneratedValueStatement; // contains the statement which should be used when query for automatically generated values + bool m_bAutoRetrievingEnabled; // set to when we should allow to query for generated values + protected: + OAutoRetrievingBase() : m_bAutoRetrievingEnabled(false) {} + virtual ~OAutoRetrievingBase(){} + + void enableAutoRetrievingEnabled(bool _bAutoEnable) { m_bAutoRetrievingEnabled = _bAutoEnable; } + void setAutoRetrievingStatement(const OUString& _sStmt) { m_sGeneratedValueStatement = _sStmt; } + public: + bool isAutoRetrievingEnabled() const { return m_bAutoRetrievingEnabled; } + + /** transform the statement to query for auto generated values + @param _sInsertStatement + The "INSERT" statement, is used to query for column and table names + @return + The transformed generated statement. + */ + OUString getTransformedGeneratedStatement(const OUString& _sInsertStatement) const; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_AUTORETRIEVINGBASE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx b/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx new file mode 100644 index 000000000..d5d9fc8ce --- /dev/null +++ b/connectivity/source/inc/FDatabaseMetaDataResultSet.hxx @@ -0,0 +1,277 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FDATABASEMETADATARESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FDATABASEMETADATARESULTSET_HXX + +#include <sal/config.h> + +#include <vector> + +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/propertycontainer.hxx> +#include <connectivity/FValue.hxx> +#include <connectivity/dbtoolsdllapi.hxx> + +namespace connectivity +{ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XCloseable, + css::lang::XInitialization, + css::lang::XServiceInfo, + css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE; + + // typedef ORefVector<ORowSetValue> ORow; + // typedef ORefVector<ORow> ORows; + + class OOO_DLLPUBLIC_DBTOOLS ODatabaseMetaDataResultSet : + public cppu::BaseMutex, + public ODatabaseMetaDataResultSet_BASE, + public ::comphelper::OPropertyContainer, + public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet> + { + + public: + typedef std::vector<ORowSetValueDecoratorRef> ORow; + typedef std::vector<ORow> ORows; + + enum MetaDataResultSetType + { + /// describes a result set as expected by XDatabaseMetaData::getCatalogs + eCatalogs = 0, + /// describes a result set as expected by XDatabaseMetaData::getSchemas + eSchemas = 1, + /// describes a result set as expected by XDatabaseMetaData::getColumnPrivileges + eColumnPrivileges = 2, + /// describes a result set as expected by XDatabaseMetaData::getColumns + eColumns = 3, + /// describes a result set as expected by XDatabaseMetaData::getTables + eTables = 4, + /// describes a result set as expected by XDatabaseMetaData::getTableTypes + eTableTypes = 5, + /// describes a result set as expected by XDatabaseMetaData::getProcedureColumns + eProcedureColumns = 6, + /// describes a result set as expected by XDatabaseMetaData::getProcedures + eProcedures = 7, + /// describes a result set as expected by XDatabaseMetaData::getExportedKeys + eExportedKeys = 8, + /// describes a result set as expected by XDatabaseMetaData::getImportedKeys + eImportedKeys = 9, + /// describes a result set as expected by XDatabaseMetaData::getPrimaryKeys + ePrimaryKeys = 10, + /// describes a result set as expected by XDatabaseMetaData::getIndexInfo + eIndexInfo = 11, + /// describes a result set as expected by XDatabaseMetaData::getTablePrivileges + eTablePrivileges = 12, + /// describes a result set as expected by XDatabaseMetaData::getCrossReference + eCrossReference = 13, + /// describes a result set as expected by XDatabaseMetaData::getTypeInfo + eTypeInfo = 14, + /// describes a result set as expected by XDatabaseMetaData::getBestRowIdentifier + eBestRowIdentifier = 15, + /// describes a result set as expected by XDatabaseMetaData::getVersionColumns + eVersionColumns = 16, + /// describes a result set as expected by XDatabaseMetaData::getUDTs + eUDTs = 17 + }; + + private: + ORowSetValue m_aEmptyValue; + css::uno::WeakReferenceHelper m_aStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData; + sal_Int32 m_nColPos; + + sal_Int32 m_nFetchSize; + sal_Int32 m_nResultSetType; + sal_Int32 m_nFetchDirection; + sal_Int32 m_nResultSetConcurrency; + + void construct(); + /// @throws css::sdbc::SQLException + void checkIndex(sal_Int32 columnIndex ); + void setType(MetaDataResultSetType _eType); + + protected: + ORows m_aRows; + ORows::iterator m_aRowsIter; + bool m_bBOF; + bool m_bEOF; + + virtual const ORowSetValue& getValue(sal_Int32 columnIndex); + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual ~ODatabaseMetaDataResultSet() override; + public: + + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + /// default construction + ODatabaseMetaDataResultSet(); + /// construction of a pre-defined result set type + ODatabaseMetaDataResultSet( MetaDataResultSetType _eType ); + + void setRows(const ORows& _rRows); + + // XServiceInfo + + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + protected: + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + void setCatalogsMap(); + void setSchemasMap(); + void setColumnPrivilegesMap(); + void setColumnsMap(); + void setTablesMap(); + void setTableTypes(); + void setProcedureColumnsMap(); + void setProceduresMap(); + void setExportedKeysMap(); + void setImportedKeysMap(); + void setPrimaryKeysMap(); + void setIndexInfoMap(); + void setTablePrivilegesMap(); + void setCrossReferenceMap(); + void setTypeInfoMap(); + void setBestRowIdentifierMap(); + void setVersionColumnsMap(); + void setUDTsMap(); + public: + // some methods to get already defined ORowSetValues + // this increase the reuse of ORowSetValues + /// return an empty ORowSetValueDecorator + static ORowSetValueDecoratorRef const & getEmptyValue(); + /// return an ORowSetValueDecorator with 0 as value + static ORowSetValueDecoratorRef const & get0Value(); + /// return an ORowSetValueDecorator with 1 as value + static ORowSetValueDecoratorRef const & get1Value(); + /// return an ORowSetValueDecorator with ColumnSearch::BASIC as value + static ORowSetValueDecoratorRef const & getBasicValue(); + /// return an ORowSetValueDecorator with string SELECT as value + static ORowSetValueDecoratorRef const & getSelectValue(); + /// return an ORowSetValueDecorator with string INSERT as value + static ORowSetValueDecoratorRef const & getInsertValue(); + /// return an ORowSetValueDecorator with string DELETE as value + static ORowSetValueDecoratorRef const & getDeleteValue(); + /// return an ORowSetValueDecorator with string UPDATE as value + static ORowSetValueDecoratorRef const & getUpdateValue(); + /// return an ORowSetValueDecorator with string CREATE as value + static ORowSetValueDecoratorRef const & getCreateValue(); + /// return an ORowSetValueDecorator with string READ as value + static ORowSetValueDecoratorRef const & getReadValue(); + /// return an ORowSetValueDecorator with string ALTER as value + static ORowSetValueDecoratorRef const & getAlterValue(); + /// return an ORowSetValueDecorator with string DROP as value + static ORowSetValueDecoratorRef const & getDropValue(); + /// return an ORowSetValueDecorator with string ' as value + static ORowSetValueDecoratorRef const & getQuoteValue(); + + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FDATABASEMETADATARESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx b/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx new file mode 100644 index 000000000..2e5ccb007 --- /dev/null +++ b/connectivity/source/inc/FDatabaseMetaDataResultSetMetaData.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FDATABASEMETADATARESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FDATABASEMETADATARESULTSETMETADATA_HXX + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include <map> +#include <vector> +#include "OColumn.hxx" + +namespace connectivity +{ + + //************ Class: ODatabaseMetaDataResultSetMetaData + + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> ODatabaseMetaResultSetMetaData_BASE; + + class ODatabaseMetaDataResultSetMetaData : public ODatabaseMetaResultSetMetaData_BASE + { + std::map<sal_Int32,connectivity::OColumn> m_mColumns; + std::map<sal_Int32,connectivity::OColumn>::const_iterator m_mColumnsIter; + + protected: + virtual ~ODatabaseMetaDataResultSetMetaData() override; + public: + // a Constructor, that is needed for when returning the object is needed: + ODatabaseMetaDataResultSetMetaData( ) + { + } + + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + + // methods to set the right column mapping + void setColumnPrivilegesMap(); + void setColumnMap(); + void setColumnsMap(); + void setTableNameMap(); + void setTablesMap(); + void setProcedureColumnsMap(); + void setPrimaryKeysMap(); + void setIndexInfoMap(); + void setTablePrivilegesMap(); + void setCrossReferenceMap(); + void setTypeInfoMap(); + void setProcedureNameMap(); + void setProceduresMap(); + void setTableTypes(); + void setBestRowIdentifierMap() { setVersionColumnsMap();} + void setVersionColumnsMap(); + void setExportedKeysMap() { setCrossReferenceMap(); } + void setImportedKeysMap() { setCrossReferenceMap(); } + void setCatalogsMap(); + void setSchemasMap(); + void setUDTsMap(); + }; +} +#endif // _CONNECTIVITY_FILE_ADATABASEMETARESULTSETMETADATA_HXX_ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/OColumn.hxx b/connectivity/source/inc/OColumn.hxx new file mode 100644 index 000000000..a60f44e2b --- /dev/null +++ b/connectivity/source/inc/OColumn.hxx @@ -0,0 +1,121 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_OCOLUMN_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_OCOLUMN_HXX + +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <connectivity/dbtoolsdllapi.hxx> + +namespace connectivity +{ + class OOO_DLLPUBLIC_DBTOOLS OColumn + { + OUString m_TableName; + OUString m_ColumnName; + OUString m_ColumnLabel; + + sal_Int32 m_Nullable; + sal_Int32 m_ColumnDisplaySize; + sal_Int32 m_Precision; + sal_Int32 m_Scale; + sal_Int32 m_ColumnType; + + bool m_AutoIncrement; + bool m_CaseSensitive; + bool m_Searchable; + bool m_Currency; + bool m_Signed; + bool m_ReadOnly; + bool m_Writable; + bool m_DefinitelyWritable; + + public: + OColumn() + : m_Nullable(0) + , m_ColumnDisplaySize(0) + , m_Precision(0) + , m_Scale(0) + , m_ColumnType(0) + + , m_AutoIncrement(false) + , m_CaseSensitive(false) + , m_Searchable(true) + , m_Currency(false) + , m_Signed(false) + , m_ReadOnly(true) + , m_Writable(false) + , m_DefinitelyWritable(false) + {} + + OColumn(const OUString &_aTableName, + const OUString &_aColumnName, + sal_Int32 _aNullable, + sal_Int32 _aColumnDisplaySize, + sal_Int32 _aPrecision, + sal_Int32 _aScale, + sal_Int32 _aColumnType) + : m_TableName(_aTableName), + m_ColumnName(_aColumnName), + m_ColumnLabel(), + + m_Nullable(_aNullable), + m_ColumnDisplaySize(_aColumnDisplaySize), + m_Precision(_aPrecision), + m_Scale(_aScale), + m_ColumnType(_aColumnType), + + m_AutoIncrement(false), + m_CaseSensitive(false), + m_Searchable(true), + m_Currency(false), + m_Signed(false), + m_ReadOnly(true), + m_Writable(false), + m_DefinitelyWritable(false) + { + if(m_ColumnLabel.isEmpty()) + m_ColumnLabel = _aColumnName; + } + + bool isAutoIncrement() const { return m_AutoIncrement; } + bool isCaseSensitive() const { return m_CaseSensitive; } + bool isSearchable() const { return m_Searchable; } + bool isCurrency() const { return m_Currency; } + bool isSigned() const { return m_Signed; } + bool isReadOnly() const { return m_ReadOnly; } + bool isWritable() const { return m_Writable; } + bool isDefinitelyWritable() const { return m_DefinitelyWritable; } + + sal_Int32 isNullable() const { return m_Nullable; } + sal_Int32 getColumnDisplaySize() const { return m_ColumnDisplaySize; } + sal_Int32 getPrecision() const { return m_Precision; } + sal_Int32 getScale() const { return m_Scale; } + sal_Int32 getColumnType() const { return m_ColumnType; } + + const OUString& getColumnLabel() const { return m_ColumnLabel; } + const OUString& getColumnName() const { return m_ColumnName; } + const OUString& getTableName() const { return m_TableName; } + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_OCOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/OTypeInfo.hxx b/connectivity/source/inc/OTypeInfo.hxx new file mode 100644 index 000000000..772a46223 --- /dev/null +++ b/connectivity/source/inc/OTypeInfo.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_OTYPEINFO_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_OTYPEINFO_HXX + +#include <com/sun/star/sdbc/DataType.hpp> + +#include <rtl/ustring.hxx> + +namespace connectivity +{ + struct OTypeInfo + { + OUString aTypeName; // Name of the type in the database + OUString aLocalTypeName; + + sal_Int32 nPrecision; // Length of the type + + sal_Int16 nMaximumScale; // Decimal places + + sal_Int16 nType; // Database type + + OTypeInfo() + :nPrecision(0) + ,nMaximumScale(0) + ,nType( css::sdbc::DataType::OTHER) + {} + + bool operator == (const OTypeInfo& lh) const { return lh.nType == nType; } + bool operator != (const OTypeInfo& lh) const { return lh.nType != nType; } + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_OTYPEINFO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ParameterSubstitution.hxx b/connectivity/source/inc/ParameterSubstitution.hxx new file mode 100644 index 000000000..59d9b1a91 --- /dev/null +++ b/connectivity/source/inc/ParameterSubstitution.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_PARAMETERSUBSTITUTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_PARAMETERSUBSTITUTION_HXX + +#include <com/sun/star/util/XStringSubstitution.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/weakref.hxx> + +namespace connectivity +{ + typedef ::cppu::WeakImplHelper< css::util::XStringSubstitution + ,css::lang::XServiceInfo + ,css::lang::XInitialization > ParameterSubstitution_BASE; + class ParameterSubstitution final : public ParameterSubstitution_BASE + { + ::osl::Mutex m_aMutex; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::WeakReference< css::sdbc::XConnection > m_xConnection; + + ParameterSubstitution( const ParameterSubstitution& ) = delete; + ParameterSubstitution& operator=( const ParameterSubstitution& ) = delete; + public: + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > create( const css::uno::Reference< css::uno::XComponentContext > & xContext); + private: + ParameterSubstitution(const css::uno::Reference< css::uno::XComponentContext >& _rxContext ); + virtual ~ParameterSubstitution() override {} + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XStringSubstitution + virtual OUString SAL_CALL substituteVariables( const OUString& aText, sal_Bool bSubstRequired ) override; + virtual OUString SAL_CALL reSubstituteVariables( const OUString& aText ) override; + virtual OUString SAL_CALL getSubstituteVariableValue( const OUString& variable ) override; + }; + +} // connectivity + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/RowFunctionParser.hxx b/connectivity/source/inc/RowFunctionParser.hxx new file mode 100644 index 000000000..5bb508bc1 --- /dev/null +++ b/connectivity/source/inc/RowFunctionParser.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ROWFUNCTIONPARSER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ROWFUNCTIONPARSER_HXX + +#include <sal/config.h> +#include "FDatabaseMetaDataResultSet.hxx" +#include <connectivity/dbtoolsdllapi.hxx> +#include <memory> + +namespace connectivity +{ + +enum class ExpressionFunct +{ + Equation, + And, + Or +}; + +#define EXPRESSION_FLAG_SUMANGLE_MODE 1 + +class OOO_DLLPUBLIC_DBTOOLS SAL_NO_VTABLE ExpressionNode +{ +public: + virtual ~ExpressionNode(){} + + /** Operator to calculate function value. + + This method calculates the function value. + */ + virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const = 0; + + virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const = 0; +}; + +/** This exception is thrown, when the arithmetic expression + parser failed to parse a string. + */ +struct OOO_DLLPUBLIC_DBTOOLS ParseError +{ + ParseError( const char* ) {} +}; + +class FunctionParser +{ +public: + + /** Parse a string + + The following grammar is accepted by this method: + <code> + + number_digit = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' + + number = number number_digit | number_digit + + equal_function = '=' + ternary_function = 'if' + + string_reference = 'a-z,A-Z,0-9' ' ' + modifier_reference = '$' '0-9' ' ' + + basic_expression = + number | + string_reference | + additive_expression equal_function additive_expression | + unary_function '(' number_digit ')' + ternary_function '(' additive_expression ',' additive_expression ', + ' additive_expression ')' | '(' additive_expression ')' + + </code> + + @param rFunction + The string to parse + + @throws ParseError if an invalid expression is given. + + @return the generated function object. + */ + + static std::shared_ptr<ExpressionNode> const & parseFunction( const OUString& _sFunction); + +private: + // disabled constructor/destructor, since this is + // supposed to be a singleton + FunctionParser() = delete; + FunctionParser(const FunctionParser&) = delete; + FunctionParser& operator=( const FunctionParser& ) = delete; +}; + + +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ROWFUNCTIONPARSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/TConnection.hxx b/connectivity/source/inc/TConnection.hxx new file mode 100644 index 000000000..85e6e4fac --- /dev/null +++ b/connectivity/source/inc/TConnection.hxx @@ -0,0 +1,83 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_TCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_TCONNECTION_HXX + +#include <rtl/textenc.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <cppuhelper/compbase.hxx> +#include "propertyids.hxx" +#include <connectivity/CommonTools.hxx> +#include <connectivity/dbtoolsdllapi.hxx> +#include "resource/sharedresources.hxx" + +namespace connectivity +{ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection, + css::sdbc::XWarningsSupplier, + css::lang::XServiceInfo, + css::lang::XUnoTunnel + > OMetaConnection_BASE; + + class OOO_DLLPUBLIC_DBTOOLS OMetaConnection : public OMetaConnection_BASE + { + protected: + ::osl::Mutex m_aMutex; + css::uno::Sequence< css::beans::PropertyValue > + m_aConnectionInfo; + connectivity::OWeakRefArray m_aStatements; // vector containing a list + // of all the Statement objects + // for this Connection + OUString m_sURL; + rtl_TextEncoding m_nTextEncoding; // the encoding which is used for all text conversions + css::uno::WeakReference< css::sdbc::XDatabaseMetaData > + m_xMetaData; + SharedResources m_aResources; + public: + + static ::dbtools::OPropertyMap& getPropMap(); + + OMetaConnection(); + + rtl_TextEncoding getTextEncoding() const { return m_nTextEncoding; } + const OUString& getURL() const { return m_sURL; } + void setURL(const OUString& _rsUrl) { m_sURL = _rsUrl; } + void throwGenericSQLException(const char* pErrorResourceId, const css::uno::Reference< css::uno::XInterface>& _xContext); + const SharedResources& getResources() const { return m_aResources;} + + void setConnectionInfo(const css::uno::Sequence< css::beans::PropertyValue >& _aInfo) { m_aConnectionInfo = _aInfo; } + const css::uno::Sequence< css::beans::PropertyValue >& + getConnectionInfo() const { return m_aConnectionInfo; } + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + //XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_TCONNECTION_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/TDatabaseMetaDataBase.hxx b/connectivity/source/inc/TDatabaseMetaDataBase.hxx new file mode 100644 index 000000000..a13adf215 --- /dev/null +++ b/connectivity/source/inc/TDatabaseMetaDataBase.hxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_TDATABASEMETADATABASE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_TDATABASEMETADATABASE_HXX + +#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/lang/XEventListener.hpp> +#include "FDatabaseMetaDataResultSet.hxx" +#include <functional> +#include <connectivity/dbtoolsdllapi.hxx> + +namespace connectivity +{ + class OOO_DLLPUBLIC_DBTOOLS ODatabaseMetaDataBase : + public cppu::BaseMutex, + public ::cppu::WeakImplHelper< css::sdbc::XDatabaseMetaData2, + css::lang::XEventListener> + { + private: + css::uno::Sequence< css::beans::PropertyValue > m_aConnectionInfo; + ::connectivity::ODatabaseMetaDataResultSet::ORows m_aTypeInfoRows; + + // cached database information + std::pair<bool,bool> m_isCatalogAtStart; + std::pair<bool,OUString> m_sCatalogSeparator; + std::pair<bool,OUString> m_sIdentifierQuoteString; + std::pair<bool,bool> m_supportsCatalogsInTableDefinitions; + std::pair<bool,bool> m_supportsSchemasInTableDefinitions; + std::pair<bool,bool> m_supportsCatalogsInDataManipulation; + std::pair<bool,bool> m_supportsSchemasInDataManipulation; + std::pair<bool,bool> m_supportsMixedCaseQuotedIdentifiers; + std::pair<bool,bool> m_supportsAlterTableWithAddColumn; + std::pair<bool,bool> m_supportsAlterTableWithDropColumn; + std::pair<bool,sal_Int32> m_MaxStatements; + std::pair<bool,sal_Int32> m_MaxTablesInSelect; + std::pair<bool,bool> m_storesMixedCaseQuotedIdentifiers; + + template <typename T> T callImplMethod(std::pair<bool,T>& _rCache,const std::function<T(ODatabaseMetaDataBase *)>& _pImplMethod) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !_rCache.first ) + { + _rCache.second = _pImplMethod(this); + _rCache.first = true; + } + return _rCache.second; + } + protected: + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + css::uno::Reference< css::lang::XEventListener> m_xListenerHelper; // forward the calls from the connection to me + + virtual ~ODatabaseMetaDataBase() override; + + protected: + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() = 0; + // cached database information + virtual OUString impl_getIdentifierQuoteString_throw( ) = 0; + virtual bool impl_isCatalogAtStart_throw( ) = 0; + virtual OUString impl_getCatalogSeparator_throw( ) = 0; + virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) = 0; + virtual bool impl_supportsSchemasInTableDefinitions_throw( ) = 0; + virtual bool impl_supportsCatalogsInDataManipulation_throw( ) = 0; + virtual bool impl_supportsSchemasInDataManipulation_throw( ) = 0; + virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) = 0; + virtual bool impl_supportsAlterTableWithAddColumn_throw( ) = 0; + virtual bool impl_supportsAlterTableWithDropColumn_throw( ) = 0; + virtual sal_Int32 impl_getMaxStatements_throw( ) = 0; + virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) = 0; + virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) = 0; + + + public: + + ODatabaseMetaDataBase(const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,const css::uno::Sequence< css::beans::PropertyValue >& _rInfo); + + // XDatabaseMetaData2 + virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getConnectionInfo( ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTypeInfo( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + // cached database information + virtual OUString SAL_CALL getIdentifierQuoteString( ) override; + virtual sal_Bool SAL_CALL isCatalogAtStart( ) override; + virtual OUString SAL_CALL getCatalogSeparator( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInTableDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInDataManipulation( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override; + virtual sal_Int32 SAL_CALL getMaxStatements( ) override; + virtual sal_Int32 SAL_CALL getMaxTablesInSelect( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseQuotedIdentifiers( ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_TDATABASEMETADATABASE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/TKeyValue.hxx b/connectivity/source/inc/TKeyValue.hxx new file mode 100644 index 000000000..abf61a4c7 --- /dev/null +++ b/connectivity/source/inc/TKeyValue.hxx @@ -0,0 +1,62 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_TKEYVALUE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_TKEYVALUE_HXX + +#include <connectivity/FValue.hxx> +#include <connectivity/dbtoolsdllapi.hxx> +#include <osl/diagnose.h> + +namespace connectivity +{ + class OOO_DLLPUBLIC_DBTOOLS OKeyValue final + { + std::vector<ORowSetValueDecoratorRef> m_aKeys; + sal_Int32 m_nValue; + + OKeyValue(sal_Int32 nVal); + public: + + ~OKeyValue(); + + static std::unique_ptr<OKeyValue> createKeyValue(sal_Int32 nVal); + + void pushKey(const ORowSetValueDecoratorRef& _aValueRef) + { + m_aKeys.push_back(_aValueRef); + } + + OUString getKeyString(std::vector<ORowSetValueDecoratorRef>::size_type i) const + { + OSL_ENSURE(m_aKeys.size() > i,"Wrong index for KEyValue"); + return m_aKeys[i]->getValue(); + } + double getKeyDouble(std::vector<ORowSetValueDecoratorRef>::size_type i) const + { + OSL_ENSURE(m_aKeys.size() > i,"Wrong index for KEyValue"); + return m_aKeys[i]->getValue(); + } + + sal_Int32 getValue() const { return m_nValue; } + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_TKEYVALUE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/TPrivilegesResultSet.hxx b/connectivity/source/inc/TPrivilegesResultSet.hxx new file mode 100644 index 000000000..d8f31194d --- /dev/null +++ b/connectivity/source/inc/TPrivilegesResultSet.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_TPRIVILEGESRESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_TPRIVILEGESRESULTSET_HXX + +#include "FDatabaseMetaDataResultSet.hxx" +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <connectivity/dbtoolsdllapi.hxx> + +namespace connectivity +{ + class OOO_DLLPUBLIC_DBTOOLS OResultSetPrivileges : + public ODatabaseMetaDataResultSet + { + css::uno::Reference< css::sdbc::XResultSet> m_xTables; + css::uno::Reference< css::sdbc::XRow> m_xRow; + bool m_bResetValues; + protected: + virtual const ORowSetValue& getValue(sal_Int32 columnIndex) override; + public: + OResultSetPrivileges(const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _rxMeta + ,const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern); + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_TPRIVILEGESRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/TResultSetHelper.hxx b/connectivity/source/inc/TResultSetHelper.hxx new file mode 100644 index 000000000..e6c0efd9c --- /dev/null +++ b/connectivity/source/inc/TResultSetHelper.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_TRESULTSETHELPER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_TRESULTSETHELPER_HXX + +#include <sal/types.h> +#include <connectivity/dbtoolsdllapi.hxx> + +namespace connectivity +{ + class OOO_DLLPUBLIC_DBTOOLS SAL_NO_VTABLE IResultSetHelper + { + public: + enum Movement + { + NEXT = 0, + PRIOR, + FIRST, + LAST, + // Named like this to avoid conflict with a #define in the Windows system ODBC headers. + RELATIVE1, + ABSOLUTE1, + BOOKMARK, + }; + public: + virtual bool move(Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) = 0; + virtual sal_Int32 getDriverPos() const = 0; + virtual bool isRowDeleted() const = 0; + + protected: + ~IResultSetHelper() {} + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_TRESULTSETHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/TSkipDeletedSet.hxx b/connectivity/source/inc/TSkipDeletedSet.hxx new file mode 100644 index 000000000..393526469 --- /dev/null +++ b/connectivity/source/inc/TSkipDeletedSet.hxx @@ -0,0 +1,82 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_TSKIPDELETEDSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_TSKIPDELETEDSET_HXX + +#include "TResultSetHelper.hxx" +#include <vector> +#include <connectivity/dbtoolsdllapi.hxx> + +namespace connectivity +{ + /** + the class OSkipDeletedSet supports a general method to skip deleted rows + */ + class OOO_DLLPUBLIC_DBTOOLS OSkipDeletedSet + { + std::vector<sal_Int32> m_aBookmarksPositions;// vector of iterators to position map, the order is the logical position + IResultSetHelper* m_pHelper; // used for moving in the resultset + bool m_bDeletedVisible; + + bool moveAbsolute(sal_Int32 _nOffset,bool _bRetrieveData); + public: + OSkipDeletedSet(IResultSetHelper* _pHelper); + ~OSkipDeletedSet(); + + /** + skipDeleted moves the resultset to the position defined by the parameters + it guarantees that the row isn't deleted + @param + IResultSetHelper::Movement _eCursorPosition in which direction the resultset should be moved + sal_Int32 _nOffset the position relative to the movement + sal_Bool _bRetrieveData is true when the current row should be filled which data + @return + true when the movement was successful otherwise false + */ + bool skipDeleted(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData); + /** + clear the map and the vector used in this class + */ + void clear(); + /** + getMappedPosition returns the mapped position of a logical position + @param + sal_Int32 _nBookmark the logical position + + @return the mapped position + */ + sal_Int32 getMappedPosition(sal_Int32 _nBookmark) const; + /** + insertNewPosition adds a new position to the map + @param + sal_Int32 _nPos the logical position + */ + void insertNewPosition(sal_Int32 _nPos); + /** + deletePosition deletes this position from the map and decrement all following positions + @param + sal_Int32 _nPos the logical position + */ + void deletePosition(sal_Int32 _nPos); + void SetDeletedVisible(bool _bDeletedVisible) { m_bDeletedVisible = _bDeletedVisible; } + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_TSKIPDELETEDSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/TSortIndex.hxx b/connectivity/source/inc/TSortIndex.hxx new file mode 100644 index 000000000..c0354316e --- /dev/null +++ b/connectivity/source/inc/TSortIndex.hxx @@ -0,0 +1,112 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_TSORTINDEX_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_TSORTINDEX_HXX + +#include <connectivity/dbtoolsdllapi.hxx> +#include "TKeyValue.hxx" + +namespace connectivity +{ + enum class OKeyType + { + NONE, // do not sort + Double, // numeric key + String // String Key + }; + + enum class TAscendingOrder + { + ASC = 1, // ascending + DESC = -1 // otherwise + }; + + class OKeySet; + class OKeyValue; // simple class which holds a sal_Int32 and a std::vector<ORowSetValueDecoratorRef> + + /** + The class OSortIndex can be used to implement a sorted index. + This can depend on the fields which should be sorted. + */ + class OOO_DLLPUBLIC_DBTOOLS OSortIndex + { + public: + typedef std::vector<std::pair<sal_Int32, std::unique_ptr<OKeyValue>>> TIntValuePairVector; + typedef std::vector<OKeyType> TKeyTypeVector; + + private: + TIntValuePairVector m_aKeyValues; + TKeyTypeVector m_aKeyType; + std::vector<TAscendingOrder> m_aAscending; + bool m_bFrozen; + + public: + + OSortIndex( const std::vector<OKeyType>& _aKeyType, + const std::vector<TAscendingOrder>& _aAscending); + OSortIndex(OSortIndex const &) = delete; // MSVC2015 workaround + OSortIndex& operator=(OSortIndex const &) = delete; // MSVC2015 workaround + + ~OSortIndex(); + + /** + AddKeyValue appends a new value. + @param + pKeyValue the keyvalue to be appended + ATTENTION: when the sortindex is already frozen the parameter will be deleted + */ + void AddKeyValue(std::unique_ptr<OKeyValue> pKeyValue); + + /** + Freeze freezes the sortindex so that new values could only be appended by their value + */ + void Freeze(); + + /** + CreateKeySet creates the keyset which values could be used to travel in your table/result + The returned keyset is frozen. + */ + ::rtl::Reference<OKeySet> CreateKeySet(); + + const std::vector<OKeyType>& getKeyType() const { return m_aKeyType; } + TAscendingOrder getAscending(std::vector<TAscendingOrder>::size_type _nPos) const { return m_aAscending[_nPos]; } + + }; + + // MSVC hack to avoid multiply defined std::vector-related symbols: + class OKeySet_Base: public ORefVector<sal_Int32> {}; + + /** + The class OKeySet is a refcountable vector which also has a state. + This state gives information about if the keyset is fixed. + */ + class OOO_DLLPUBLIC_DBTOOLS OKeySet : public OKeySet_Base + { + bool m_bFrozen; + public: + OKeySet() + : m_bFrozen(false){} + + bool isFrozen() const { return m_bFrozen; } + void setFrozen() { m_bFrozen = true; } + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_TSORTINDEX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/ACallableStatement.hxx b/connectivity/source/inc/ado/ACallableStatement.hxx new file mode 100644 index 000000000..6d6979e40 --- /dev/null +++ b/connectivity/source/inc/ado/ACallableStatement.hxx @@ -0,0 +1,81 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACALLABLESTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACALLABLESTATEMENT_HXX + +#include <ado/APreparedStatement.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XOutParameters.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace connectivity +{ + namespace ado + { + + //************ Class: java.sql.CallableStatement + + + class OCallableStatement : public OPreparedStatement, + public css::sdbc::XRow, + public css::sdbc::XOutParameters + { + OLEVariant m_aValue; + public: + DECLARE_SERVICE_INFO(); + + // a Constructor, that is needed for when Returning the Object is needed: + OCallableStatement( OConnection* _pConnection, const OUString& sql ); + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XOutParameters + virtual void SAL_CALL registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) override; + }; + } +} +#endif // _CONNECTIVITY_OCallableStatement_HXX_ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/ACatalog.hxx b/connectivity/source/inc/ado/ACatalog.hxx new file mode 100644 index 000000000..d1d8e22bf --- /dev/null +++ b/connectivity/source/inc/ado/ACatalog.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACATALOG_HXX + +#include <sdbcx/VCatalog.hxx> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + class OConnection; + + class OCatalog : public connectivity::sdbcx::OCatalog + { + WpADOCatalog m_aCatalog; + OConnection* m_pConnection; + + public: + virtual void refreshTables() override; + virtual void refreshViews() override; + virtual void refreshGroups() override; + virtual void refreshUsers() override; + + public: + OCatalog(_ADOCatalog* _pCatalog,OConnection* _pCon); + ~OCatalog() override; + + OConnection* getConnection() const { return m_pConnection; } + sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); } + WpADOCatalog getCatalog() const { return m_aCatalog; } + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AColumn.hxx b/connectivity/source/inc/ado/AColumn.hxx new file mode 100644 index 000000000..cc49f3b36 --- /dev/null +++ b/connectivity/source/inc/ado/AColumn.hxx @@ -0,0 +1,60 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACOLUMN_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACOLUMN_HXX + +#include <connectivity/sdbcx/VColumn.hxx> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + class OConnection; + typedef sdbcx::OColumn OColumn_ADO; + class OAdoColumn : public OColumn_ADO + { + WpADOColumn m_aColumn; + OConnection* m_pConnection; + OUString m_ReferencedColumn; + bool m_IsAscending; + + void fillPropertyValues(); + protected: + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + public: + OAdoColumn(bool _bCase,OConnection* _pConnection,_ADOColumn* _pColumn); + OAdoColumn(bool _bCase,OConnection* _pConnection); + // ODescriptor + virtual void construct() override; + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + WpADOColumn getColumnImpl() const; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AColumns.hxx b/connectivity/source/inc/ado/AColumns.hxx new file mode 100644 index 000000000..6b605df7c --- /dev/null +++ b/connectivity/source/inc/ado/AColumns.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACOLUMNS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <connectivity/sdbcx/IRefreshable.hxx> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + class OConnection; + class OColumns : public sdbcx::OCollection + { + protected: + WpADOColumns m_aCollection; + OConnection* m_pConnection; + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override; + public: + OColumns( ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const WpADOColumns& _rCollection, + bool _bCase, + OConnection* _pConnection) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector) + ,m_aCollection(_rCollection) + ,m_pConnection(_pConnection) + { + } + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AConnection.hxx b/connectivity/source/inc/ado/AConnection.hxx new file mode 100644 index 000000000..21bc9129c --- /dev/null +++ b/connectivity/source/inc/ado/AConnection.hxx @@ -0,0 +1,138 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACONNECTION_HXX + +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <map> +#include <connectivity/CommonTools.hxx> +#include <OTypeInfo.hxx> +#include <TConnection.hxx> +#include <ado/Awrapado.hxx> + +namespace connectivity +{ + namespace ado + { + struct OExtendedTypeInfo + { + ::connectivity::OTypeInfo aSimpleType; // the general type info + DataTypeEnum eType; + + OUString getDBName() const { return aSimpleType.aTypeName; } + }; + + class WpADOConnection; + class ODriver; + class OCatalog; + typedef std::multimap<DataTypeEnum, OExtendedTypeInfo*> OTypeInfoMap; + typedef connectivity::OMetaConnection OConnection_BASE; + + + class OConnection : public OConnection_BASE + { + protected: + + // Data attributes + + OTypeInfoMap m_aTypeInfo; // vector containing an entry + // for each row returned by + // DatabaseMetaData.getTypeInfo. + css::uno::WeakReference< css::sdbcx::XTablesSupplier> m_xCatalog; + ODriver* m_pDriver; + private: + WpADOConnection* m_pAdoConnection; + OCatalog* m_pCatalog; + sal_Int32 m_nEngineType; + bool m_bClosed; + bool m_bAutocommit; + + protected: + /// @throws css::sdbc::SQLException + void buildTypeInfo(); + public: + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OConnection(ODriver* _pDriver); + // OConnection(const SQLHANDLE _pConnectionHandle); + ~OConnection() override; + void construct(const OUString& url,const css::uno::Sequence< css::beans::PropertyValue >& info); + + //XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + // XServiceInfo + DECLARE_SERVICE_INFO(); + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + + WpADOConnection* getConnection() { return m_pAdoConnection; } + void setCatalog(const css::uno::WeakReference< css::sdbcx::XTablesSupplier>& _xCat) { m_xCatalog = _xCat; } + void setCatalog(OCatalog* _pCatalog) { m_pCatalog = _pCatalog; } + + const OTypeInfoMap* getTypeInfo() const { return &m_aTypeInfo;} + OCatalog* getAdoCatalog() const + { + if ( m_xCatalog.get().is() ) + return m_pCatalog; + return nullptr; + } + + sal_Int32 getEngineType() const { return m_nEngineType; } + ODriver* getDriver() const { return m_pDriver; } + + static const OExtendedTypeInfo* getTypeInfoFromType(const OTypeInfoMap& _rTypeInfo, + DataTypeEnum _nType, + const OUString& _sTypeName, + sal_Int32 _nPrecision, + sal_Int32 _nScale, + bool& _brForceToType); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ACONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/ADatabaseMetaData.hxx b/connectivity/source/inc/ado/ADatabaseMetaData.hxx new file mode 100644 index 000000000..83a84f3bd --- /dev/null +++ b/connectivity/source/inc/ado/ADatabaseMetaData.hxx @@ -0,0 +1,226 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADATABASEMETADATA_HXX + +#include <TDatabaseMetaDataBase.hxx> +#include <map> + +namespace connectivity +{ + namespace ado + { + class WpADOConnection; + class OConnection; + + //************ Class: ODatabaseMetaData + + + class ODatabaseMetaData : public ODatabaseMetaDataBase + { + struct LiteralInfo + { + OUString pwszLiteralValue; + sal_uInt32 cchMaxLen; + bool fSupported; + }; + + std::map<sal_uInt32,LiteralInfo> m_aLiteralInfo; + WpADOConnection* m_pADOConnection; + OConnection* m_pConnection; + + void fillLiterals(); + // get information out of rowset + sal_Int32 getMaxSize(sal_uInt32 _nId); + bool isCapable(sal_uInt32 _nId); + OUString getLiteral(sal_uInt32 _nProperty); + + // get info out of properties + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OUString getStringProperty(const OUString& _aProperty); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getInt32Property(const OUString& _aProperty); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + bool getBoolProperty(const OUString& _aProperty); + + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + // cached database information + virtual OUString impl_getIdentifierQuoteString_throw( ) override; + virtual bool impl_isCatalogAtStart_throw( ) override; + virtual OUString impl_getCatalogSeparator_throw( ) override; + virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override; + virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override; + virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override; + virtual bool impl_supportsSchemasInDataManipulation_throw( ) override; + virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override; + virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override; + virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override; + virtual sal_Int32 impl_getMaxStatements_throw( ) override; + virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override; + virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override; + public: + + ODatabaseMetaData(OConnection* _pCon); + + // XDatabaseMetaData + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADATABASEMETADATA_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx b/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx new file mode 100644 index 000000000..4d99bdce3 --- /dev/null +++ b/connectivity/source/inc/ado/ADatabaseMetaDataResultSet.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADATABASEMETADATARESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADATABASEMETADATARESULTSET_HXX + +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <comphelper/proparrhlp.hxx> +#include <ado/AStatement.hxx> + +namespace connectivity +{ + namespace ado + { + /* + ** java_sql_ResultSet + */ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE; + + class ODatabaseMetaDataResultSet : public cppu::BaseMutex, + public ODatabaseMetaDataResultSet_BASE, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet> + { + std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time + + std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> > m_aValueRange; + std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> >::iterator m_aValueRangeIter; + + std::map<sal_Int32, std::map< OUString,sal_Int32> > m_aStrValueRange; + std::map<sal_Int32, std::map< OUString,sal_Int32> >::iterator m_aStrValueRangeIter; + + std::map<sal_Int32, std::map< sal_Int32,OUString> > m_aIntValueRange; + std::map<sal_Int32, std::map< sal_Int32,OUString> >::iterator m_aIntValueRangeIter; + + ADORecordset* m_pRecordSet; + css::uno::WeakReferenceHelper m_aStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData; + OLEVariant m_aValue; + sal_Int32 m_nRowPos; + bool m_bWasNull; + bool m_bEOF; + bool m_bOnFirstAfterOpen; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static sal_Int32 getResultSetConcurrency(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static sal_Int32 getResultSetType(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static sal_Int32 getFetchDirection(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getFetchSize() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static OUString getCursorName(); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchDirection(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchSize(sal_Int32 _par0); + + + inline sal_Int32 mapColumn (sal_Int32 column); + /// @throws css::sdbc::SQLException + void checkRecordSet(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OLEVariant getValue(sal_Int32 columnIndex ); + + protected: + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + public: + // a Constructor, that is needed for when Returning the Object is needed: + ODatabaseMetaDataResultSet( ADORecordset* _pRecordSet); + ~ODatabaseMetaDataResultSet() override; + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + + const std::vector<sal_Int32>& getColumnMapping() { return m_aColMapping; } + + void setCatalogsMap(); + void setSchemasMap(); + void setColumnPrivilegesMap(); + void setColumnsMap(); + void setTablesMap(); + void setProcedureColumnsMap(); + void setProceduresMap(); + void setExportedKeysMap(); + void setImportedKeysMap(); + void setPrimaryKeysMap(); + void setIndexInfoMap(); + void setTablePrivilegesMap(); + void setCrossReferenceMap(); + void setTypeInfoMap(bool _bJetEngine); + }; + + inline sal_Int32 ODatabaseMetaDataResultSet::mapColumn (sal_Int32 column) + { + sal_Int32 map = column; + + if (!m_aColMapping.empty()) + { + // Validate column number + map = m_aColMapping[column]; + } + + return map; + } + } + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADATABASEMETADATARESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx b/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx new file mode 100644 index 000000000..714aa9136 --- /dev/null +++ b/connectivity/source/inc/ado/ADatabaseMetaDataResultSetMetaData.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADATABASEMETADATARESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADATABASEMETADATARESULTSETMETADATA_HXX + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include <vector> +#include <ado/Awrapado.hxx> +#include <ado/ADatabaseMetaDataResultSet.hxx> +#include <OColumn.hxx> + +namespace connectivity +{ + namespace ado + { + + //************ Class: ResultSetMetaData + + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> ODatabaseMetaResultSetMetaData_BASE; + + class ODatabaseMetaDataResultSetMetaData : public ODatabaseMetaResultSetMetaData_BASE + { + friend class ODatabaseMetaDataResultSet; + + const std::vector<sal_Int32> &m_vMapping; // when not every column is needed + std::map<sal_Int32,connectivity::OColumn> m_mColumns; + std::map<sal_Int32,connectivity::OColumn>::const_iterator m_mColumnsIter; + + ADORecordset* m_pRecordSet; + sal_Int32 m_nColCount; + + private: + ODatabaseMetaDataResultSetMetaData( const ODatabaseMetaDataResultSetMetaData& ); // never implemented + ODatabaseMetaDataResultSetMetaData& operator=( const ODatabaseMetaDataResultSetMetaData& ); // never implemented + + protected: + void setColumnPrivilegesMap(); + void setColumnsMap(); + void setTablesMap(); + void setProcedureColumnsMap(); + void setPrimaryKeysMap(); + void setIndexInfoMap(); + void setTablePrivilegesMap(); + void setCrossReferenceMap(); + void setTypeInfoMap(); + void setProceduresMap(); + public: + // a Constructor, that is needed for when Returning the Object is needed: + ODatabaseMetaDataResultSetMetaData( ADORecordset* _pRecordSet ,ODatabaseMetaDataResultSet* _pRes) + : m_vMapping(_pRes->getColumnMapping()), + m_pRecordSet(_pRecordSet), + m_nColCount(m_vMapping.size()-1) + { + if(m_pRecordSet) + m_pRecordSet->AddRef(); + } + ~ODatabaseMetaDataResultSetMetaData() override; + + /// Avoid ambiguous cast error from the compiler. + operator css::uno::Reference< css::sdbc::XResultSetMetaData > () throw() + { return this; } + + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + } +} +#endif // _CONNECTIVITY_ADO_ADATABASEMETARESULTSETMETADATA_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/ADriver.hxx b/connectivity/source/inc/ado/ADriver.hxx new file mode 100644 index 000000000..22b23b4ca --- /dev/null +++ b/connectivity/source/inc/ado/ADriver.hxx @@ -0,0 +1,90 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADRIVER_HXX + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/compbase.hxx> +#include <connectivity/CommonTools.hxx> + +namespace com::sun::star::lang { class XMultiServiceFactory; } + +namespace connectivity +{ + namespace ado + { + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver, + css::sdbcx::XDataDefinitionSupplier, + css::lang::XServiceInfo + > ODriver_BASE; + class ODriver : public ODriver_BASE + { + ::osl::Mutex m_aMutex; + + connectivity::OWeakRefArray m_xConnections; // vector containing a list + // of all the Connection objects + // for this Driver + css::uno::Reference< css::lang::XMultiServiceFactory > m_xORB; + + + public: + ODriver(const css::uno::Reference< css::lang::XMultiServiceFactory >& _xORB); + ~ODriver() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + css::uno::Reference< css::lang::XMultiServiceFactory > getORB() const { return m_xORB; } + + private: + void impl_checkURL_throw(const OUString& _sUrl); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + + // XDataDefinitionSupplier + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + }; + } + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADRIVER_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AGroup.hxx b/connectivity/source/inc/ado/AGroup.hxx new file mode 100644 index 000000000..2b3f36fff --- /dev/null +++ b/connectivity/source/inc/ado/AGroup.hxx @@ -0,0 +1,67 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AGROUP_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AGROUP_HXX + +#include <sdbcx/VGroup.hxx> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + typedef sdbcx::OGroup OGroup_ADO; + class OCatalog; + + class OAdoGroup : public OGroup_ADO + { + WpADOGroup m_aGroup; + OCatalog* m_pCatalog; + + static sal_Int32 MapRight(RightsEnum _eNum); + static RightsEnum Map2Right(sal_Int32 _eNum); + static ObjectTypeEnum MapObjectType(sal_Int32 ObjType); + protected: + virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue,sal_Int32 nHandle) const override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override; + + public: + virtual void refreshUsers() override; + public: + OAdoGroup(OCatalog* _pParent,bool _bCase, ADOGroup* _pGroup=nullptr); + OAdoGroup(OCatalog* _pParent,bool _bCase, const OUString& Name); + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + // XAuthorizable + virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + + WpADOGroup getImpl() const { return m_aGroup; } + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AGROUP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AGroups.hxx b/connectivity/source/inc/ado/AGroups.hxx new file mode 100644 index 000000000..1676b9a6c --- /dev/null +++ b/connectivity/source/inc/ado/AGroups.hxx @@ -0,0 +1,57 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AGROUPS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AGROUPS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <ado/Awrapadox.hxx> +#include <ado/ACatalog.hxx> + +namespace connectivity +{ + namespace ado + { + class OGroups : public sdbcx::OCollection + { + WpADOGroups m_aCollection; + OCatalog* m_pCatalog; + protected: + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override; + public: + OGroups(OCatalog* _pParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const WpADOGroups& _rCollection,bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector) + ,m_aCollection(_rCollection) + ,m_pCatalog(_pParent) + { + } + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AGROUPS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AIndex.hxx b/connectivity/source/inc/ado/AIndex.hxx new file mode 100644 index 000000000..b31bef3f8 --- /dev/null +++ b/connectivity/source/inc/ado/AIndex.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AINDEX_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AINDEX_HXX + +#include <sdbcx/VIndex.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + class OConnection; + class OAdoIndex : public sdbcx::OIndex + { + WpADOIndex m_aIndex; + OConnection* m_pConnection; + protected: + void fillPropertyValues(); + virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override; + public: + virtual void refreshColumns() override; + public: + OAdoIndex(bool _bCase, OConnection* _pConnection,ADOIndex* _pIndex); + OAdoIndex(bool _bCase, OConnection* _pConnection); + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + WpADOIndex getImpl() const { return m_aIndex;} + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AINDEX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AIndexes.hxx b/connectivity/source/inc/ado/AIndexes.hxx new file mode 100644 index 000000000..4c253cac5 --- /dev/null +++ b/connectivity/source/inc/ado/AIndexes.hxx @@ -0,0 +1,59 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AINDEXES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AINDEXES_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + class OConnection; + class OIndexes : public sdbcx::OCollection + { + WpADOIndexes m_aCollection; + OConnection* m_pConnection; + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override; + public: + OIndexes(::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const WpADOIndexes& _rCollection, + bool _bCase, + OConnection* _pConnection) + : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector) + , m_aCollection(_rCollection) + , m_pConnection(_pConnection) + { + } + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AINDEXES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AKey.hxx b/connectivity/source/inc/ado/AKey.hxx new file mode 100644 index 000000000..bd0b5a640 --- /dev/null +++ b/connectivity/source/inc/ado/AKey.hxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AKEY_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AKEY_HXX + +#include <sdbcx/VKey.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + typedef sdbcx::OKey OKey_ADO; + + class OConnection; + class OAdoKey : public OKey_ADO + { + WpADOKey m_aKey; + OConnection* m_pConnection; + protected: + void fillPropertyValues(); + virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override; + public: + virtual void refreshColumns() override; + public: + OAdoKey(bool _bCase,OConnection* _pConnection,ADOKey* _pKey); + OAdoKey(bool _bCase,OConnection* _pConnection); + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + WpADOKey getImpl() const { return m_aKey;} + // map the update/delete rules + static RuleEnum Map2Rule(sal_Int32 _eNum); + static sal_Int32 MapRule(const RuleEnum& _eNum); + + // map the keytypes + static sal_Int32 MapKeyRule(const KeyTypeEnum& _eNum); + static KeyTypeEnum Map2KeyRule(sal_Int32 _eNum); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AKEY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AKeys.hxx b/connectivity/source/inc/ado/AKeys.hxx new file mode 100644 index 000000000..35ef33e37 --- /dev/null +++ b/connectivity/source/inc/ado/AKeys.hxx @@ -0,0 +1,59 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AKEYS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AKEYS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + class OConnection; + class OKeys : public sdbcx::OCollection + { + WpADOKeys m_aCollection; + OConnection* m_pConnection; + + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override; + public: + OKeys(::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const WpADOKeys& _rCollection, + bool _bCase, + OConnection* _pConnection) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector) + ,m_aCollection(_rCollection) + ,m_pConnection(_pConnection) + { + } + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AKEYS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/APreparedStatement.hxx b/connectivity/source/inc/ado/APreparedStatement.hxx new file mode 100644 index 000000000..214f277c1 --- /dev/null +++ b/connectivity/source/inc/ado/APreparedStatement.hxx @@ -0,0 +1,115 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_APREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_APREPAREDSTATEMENT_HXX + +#include <ado/AStatement.hxx> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +// TODO: implement css::sdbc::XPreparedBatchExecution +// (empty implementations removed on 2014-06-16) + +namespace connectivity +{ + class OSQLParseNode; + namespace ado + { + + class OPreparedStatement : public OStatement_Base, + public css::sdbc::XPreparedStatement, + public css::sdbc::XParameters, + public css::sdbc::XResultSetMetaDataSupplier, + public css::lang::XServiceInfo + + { + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setParameter(sal_Int32 parameterIndex, const DataTypeEnum& _eType, sal_Int32 _nSize,const OLEVariant& Val); + void replaceParameterNodeName( OSQLParseNode const * _pNode, + const OUString& _sDefaultName, + sal_Int32& _nParameterCount); + protected: + + // Data attributes + + css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData; + ADOParameters* m_pParameters; + + virtual ~OPreparedStatement() override; + + public: + DECLARE_SERVICE_INFO(); + // a Constructor, that is needed for when Returning the Object is needed: + OPreparedStatement( OConnection* _pConnection, const OUString& sql); + + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override; + using OStatement_Base::executeQuery; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + using OStatement_Base::executeUpdate; + virtual sal_Bool SAL_CALL execute( ) override; + using OStatement_Base::execute; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // OComponentHelper + virtual void SAL_CALL disposing() override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_APREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AResultSet.hxx b/connectivity/source/inc/ado/AResultSet.hxx new file mode 100644 index 000000000..f90155333 --- /dev/null +++ b/connectivity/source/inc/ado/AResultSet.hxx @@ -0,0 +1,239 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ARESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ARESULTSET_HXX + +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <cppuhelper/compbase.hxx> +#include <comphelper/proparrhlp.hxx> +#include <ado/AStatement.hxx> +#include <cppuhelper/basemutex.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace connectivity +{ + namespace ado + { + /* + ** java_sql_ResultSet + */ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate, + css::sdbcx::XRowLocate, + css::sdbcx::XDeleteRows, + css::lang::XServiceInfo> OResultSet_BASE; + + class OResultSet : public cppu::BaseMutex, + public OResultSet_BASE, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<OResultSet> + { + + ADORecordset* m_pRecordSet; + OStatement_Base* m_pStmt; + css::uno::Reference< css::uno::XInterface> m_xStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData; + std::vector<OLEVariant> m_aBookmarks; + OLEVariant m_aValue; + ADO_LONGPTR m_nRowPos; + bool m_bEOF; + bool m_bOnFirstAfterOpen; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getResultSetConcurrency() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getResultSetType() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static sal_Int32 getFetchDirection(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getFetchSize() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static OUString getCursorName(); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchDirection(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchSize(sal_Int32 _par0); + void updateValue(sal_Int32 columnIndex,const OLEVariant& x); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OLEVariant getValue(sal_Int32 columnIndex ); + + protected: + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + virtual ~OResultSet() override; + public: + // a Constructor, that is needed for when Returning the Object is needed: + OResultSet( ADORecordset* _pRecordSet,OStatement_Base* pStmt); + OResultSet( ADORecordset* _pRecordSet); + + // late constructor + void construct(); + void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;} + + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + // XRowLocate + virtual css::uno::Any SAL_CALL getBookmark( ) override; + virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override; + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override; + virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override; + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override; + virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override; + // XDeleteRows + virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override; + + }; + } + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ARESULTSET_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AResultSetMetaData.hxx b/connectivity/source/inc/ado/AResultSetMetaData.hxx new file mode 100644 index 000000000..ebb52be02 --- /dev/null +++ b/connectivity/source/inc/ado/AResultSetMetaData.hxx @@ -0,0 +1,84 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ARESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ARESULTSETMETADATA_HXX + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include <vector> +#include <ado/Awrapado.hxx> +#include <ado/AResultSet.hxx> +#include <OColumn.hxx> + +namespace connectivity +{ + namespace ado + { + + + //************ Class: ResultSetMetaData + + typedef ::cppu::WeakImplHelper<css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE; + + class OResultSetMetaData : public OResultSetMetaData_BASE + { + friend class OResultSet; + + ADORecordset* m_pRecordSet; + sal_Int32 m_nColCount; + + sal_Int32 MapADOType2Jdbc(DataTypeEnum eType); + private: + OResultSetMetaData( const OResultSetMetaData& ); // never implemented + OResultSetMetaData& operator=( const OResultSetMetaData& ); // never implemented + + protected: + virtual ~OResultSetMetaData() override; + public: + // a Constructor, that is needed for when Returning the Object is needed: + OResultSetMetaData( ADORecordset* _pRecordSet); + + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ARESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AStatement.hxx b/connectivity/source/inc/ado/AStatement.hxx new file mode 100644 index 000000000..278a35950 --- /dev/null +++ b/connectivity/source/inc/ado/AStatement.hxx @@ -0,0 +1,221 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ASTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ASTATEMENT_HXX + +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XBatchExecution.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <comphelper/proparrhlp.hxx> +#include <ado/AConnection.hxx> +#include <vector> +#include <ado/Awrapado.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace connectivity +{ + namespace ado + { + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement, + css::sdbc::XWarningsSupplier, + css::util::XCancellable, + css::sdbc::XCloseable, + css::sdbc::XMultipleResults> OStatement_BASE; + + + //************ Class: java.sql.Statement + + class OStatement_Base : public cppu::BaseMutex, + public OStatement_BASE, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base> + + { + friend class OResultSet; + + css::sdbc::SQLWarning m_aLastWarning; + + protected: + std::vector< OUString> m_aBatchVector; + + css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created + // for this Statement + + OConnection* m_pConnection;// The owning Connection object + WpADOCommand m_Command; + WpADORecordset m_RecordSet; + OLEVariant m_RecordsAffected; + OLEVariant m_Parameters; + std::vector<connectivity::OTypeInfo> m_aTypeInfo; // Hashtable containing an entry + // for each row returned by + // DatabaseMetaData.getTypeInfo. + ADO_LONGPTR m_nMaxRows; + sal_Int32 m_nFetchSize; + LockTypeEnum m_eLockType; + CursorTypeEnum m_eCursorType; + + using OStatement_BASE::rBHelper; + private: + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getQueryTimeOut() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static sal_Int32 getMaxFieldSize(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getMaxRows() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getResultSetConcurrency() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getResultSetType() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static sal_Int32 getFetchDirection(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getFetchSize() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OUString getCursorName() const; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setQueryTimeOut(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setMaxFieldSize(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setMaxRows(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setResultSetConcurrency(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setResultSetType(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchDirection(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchSize(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setCursorName(const OUString &_par0); + + protected: + + void assignRecordSet( ADORecordset* _pRS ); + + /// @throws css::sdbc::SQLException + void reset (); + /// @throws css::sdbc::SQLException + void clearMyResultSet (); + /// @throws css::sdbc::SQLException + void setWarning (const css::sdbc::SQLWarning &ex); + /// @throws css::sdbc::SQLException + sal_Int32 getRowCount (); + sal_Int32 getPrecision ( sal_Int32 sqlType); + + void disposeResultSet(); + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + public: + OStatement_Base(OConnection* _pConnection ); + + using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >; + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override; + virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override; + virtual sal_Bool SAL_CALL execute( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + }; + + class OStatement : public OStatement_Base, + public css::sdbc::XBatchExecution, + public css::lang::XServiceInfo + { + public: + // a Constructor, that is needed for when Returning the Object is needed: + OStatement( OConnection* _pConnection) : OStatement_Base( _pConnection){}; + ~OStatement() override; + + DECLARE_SERVICE_INFO(); + + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + // XBatchExecution + virtual void SAL_CALL addBatch( const OUString& sql ) override; + virtual void SAL_CALL clearBatch( ) override; + virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ASTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/ATable.hxx b/connectivity/source/inc/ado/ATable.hxx new file mode 100644 index 000000000..51a9fd145 --- /dev/null +++ b/connectivity/source/inc/ado/ATable.hxx @@ -0,0 +1,77 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ATABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ATABLE_HXX + +#include <connectivity/sdbcx/VTable.hxx> +#include <ado/Awrapadox.hxx> +#include <ado/ACatalog.hxx> + +namespace connectivity +{ + namespace ado + { + typedef connectivity::sdbcx::OTable OTable_TYPEDEF; + typedef connectivity::sdbcx::OTableDescriptor_BASE OTableDescriptor_BASE_TYPEDEF; + + class OAdoTable : public OTable_TYPEDEF + { + WpADOTable m_aTable; + OCatalog* m_pCatalog; + + protected: + void fillPropertyValues(); + virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override; + + public: + virtual void refreshColumns() override; + virtual void refreshKeys() override; + virtual void refreshIndexes() override; + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + + public: + OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog,_ADOTable* _pTable); + OAdoTable(sdbcx::OCollection* _pTables,bool _bCase,OCatalog* _pCatalog); + + + virtual OUString SAL_CALL getName() override; + OUString getSchema() const { return m_SchemaName; } + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() const override; + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + // XRename + virtual void SAL_CALL rename( const OUString& newName ) override; + + // XAlterTable + virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void SAL_CALL alterColumnByIndex( sal_Int32 index, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + WpADOTable getImpl() const { return m_aTable;} + OCatalog* getCatalog() const { return m_pCatalog; } + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ATABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/ATables.hxx b/connectivity/source/inc/ado/ATables.hxx new file mode 100644 index 000000000..a65741862 --- /dev/null +++ b/connectivity/source/inc/ado/ATables.hxx @@ -0,0 +1,57 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ATABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ATABLES_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <ado/Awrapadox.hxx> +#include <ado/ACatalog.hxx> + +namespace connectivity +{ + namespace ado + { + class OCatalog; + class OTables : public sdbcx::OCollection + { + WpADOTables m_aCollection; + OCatalog* m_pCatalog; + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override; + public: + OTables(OCatalog* _pParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const WpADOTables& _rCollection, + bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector) + ,m_aCollection(_rCollection) + ,m_pCatalog(_pParent) + { + OSL_ENSURE(m_aCollection.IsValid(),"Collection isn't valid"); + } + void appendNew(const OUString& _rsNewTable); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ATABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AUser.hxx b/connectivity/source/inc/ado/AUser.hxx new file mode 100644 index 000000000..3b7227d36 --- /dev/null +++ b/connectivity/source/inc/ado/AUser.hxx @@ -0,0 +1,91 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AUSER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AUSER_HXX + +#include <sdbcx/VUser.hxx> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + class OCatalog; + typedef connectivity::sdbcx::OUser OUser_TYPEDEF; + typedef connectivity::sdbcx::OUser_BASE OUser_BASE_TYPEDEF; + + class OAdoUser : public OUser_TYPEDEF + { + protected: + WpADOUser m_aUser; + OCatalog* m_pCatalog; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + public: + virtual void refreshGroups() override; + public: + OAdoUser(OCatalog* _pParent,bool _bCase, ADOUser* _pUser=nullptr); + OAdoUser(OCatalog* _pParent,bool _bCase, const OUString& Name); + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + // XUser + virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override; + // XAuthorizable + virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + + WpADOUser getImpl() const { return m_aUser;} + }; + + class OUserExtend; + typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP; + + class OUserExtend : public OAdoUser, + public OUserExtend_PROP + { + protected: + OUString m_Password; + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + public: + OUserExtend(OCatalog* _pParent,bool _bCase,ADOUser* _pUser=nullptr); + OUserExtend(OCatalog* _pParent,bool _bCase,const OUString& Name); + + virtual void construct() override; + OUString getPassword() const { return m_Password;} + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AUSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AUsers.hxx b/connectivity/source/inc/ado/AUsers.hxx new file mode 100644 index 000000000..181639196 --- /dev/null +++ b/connectivity/source/inc/ado/AUsers.hxx @@ -0,0 +1,59 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AUSERS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AUSERS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <ado/Awrapadox.hxx> +#include <ado/ACatalog.hxx> + +namespace connectivity +{ + namespace ado + { + + class OUsers : public sdbcx::OCollection + { + WpADOUsers m_aCollection; + OCatalog* m_pCatalog; + public: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual void impl_refresh() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override; + public: + OUsers( OCatalog* _pParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const WpADOUsers& _rCollection, + bool _bCase) + :sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector) + ,m_aCollection(_rCollection) + ,m_pCatalog(_pParent) + { + } + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AUSERS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AView.hxx b/connectivity/source/inc/ado/AView.hxx new file mode 100644 index 000000000..1bc3dd00b --- /dev/null +++ b/connectivity/source/inc/ado/AView.hxx @@ -0,0 +1,57 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AVIEW_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AVIEW_HXX + +#include <connectivity/sdbcx/VView.hxx> +#include <ado/Awrapadox.hxx> + +namespace connectivity +{ + namespace ado + { + + typedef sdbcx::OView OView_ADO; + + class OAdoView : public OView_ADO + { + WpADOView m_aView; + + protected: + // OPropertySetHelper + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + public: + OAdoView(bool _bCase, ADOView* _pView=nullptr); + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + WpADOView getImpl() const { return m_aView;} + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/AViews.hxx b/connectivity/source/inc/ado/AViews.hxx new file mode 100644 index 000000000..1ef1a6be3 --- /dev/null +++ b/connectivity/source/inc/ado/AViews.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AVIEWS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AVIEWS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <ado/Awrapadox.hxx> +#include <ado/ACatalog.hxx> + + +namespace connectivity +{ + namespace ado + { + + class OViews : public sdbcx::OCollection + { + WpADOViews m_aCollection; + OCatalog* m_pCatalog; + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override; + public: + OViews(OCatalog* _pParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + WpADOViews const & _rCollection,bool _bCase) : sdbcx::OCollection(*_pParent,_bCase,_rMutex,_rVector) + ,m_aCollection(_rCollection) + ,m_pCatalog(_pParent) + { + } + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AVIEWS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/Aolevariant.hxx b/connectivity/source/inc/ado/Aolevariant.hxx new file mode 100644 index 000000000..732880a7c --- /dev/null +++ b/connectivity/source/inc/ado/Aolevariant.hxx @@ -0,0 +1,154 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AOLEVARIANT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AOLEVARIANT_HXX + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +#include <oaidl.h> + +namespace com +{ + namespace sun + { + namespace star + { + namespace util + { + struct Date; + struct Time; + struct DateTime; + } + } + } +} +namespace connectivity +{ + namespace ado + { + class OLEString + { + BSTR m_sStr; + public: + OLEString(); + OLEString(const BSTR& _sBStr); + OLEString(const OUString& _sBStr); + OLEString(const OLEString& _rRh) + { + OLEString::operator=(_rRh); + } + ~OLEString(); + OLEString& operator=(const OUString& _rSrc); + OLEString& operator=(const BSTR& _rSrc); + OLEString& operator=(const OLEString& _rSrc); + OUString asOUString() const; + BSTR asBSTR() const; + BSTR* getAddress(); + sal_Int32 length() const; + }; + + class OLEVariant : public ::tagVARIANT + { + public: + OLEVariant(); + OLEVariant(const VARIANT& varSrc); + OLEVariant(const OLEVariant& varSrc) ; + OLEVariant(bool x) ; + OLEVariant(sal_Bool) = delete; + OLEVariant(sal_Int8 n) ; + OLEVariant(sal_Int16 n) ; + OLEVariant(sal_Int32 n) ; + OLEVariant(sal_Int64 x) ; + + OLEVariant(const OUString& us) ; + ~OLEVariant() ; + OLEVariant(const css::util::Date& x ); + OLEVariant(const css::util::Time& x ); + OLEVariant(const css::util::DateTime& x ); + OLEVariant(float x); + OLEVariant(const double &x); + OLEVariant(IDispatch* pDispInterface); + OLEVariant(const css::uno::Sequence< sal_Int8 >& x); + OLEVariant& operator=(const OLEVariant& varSrc); + // Assign a const VARIANT& (::VariantCopy handles everything) + + OLEVariant& operator=(const tagVARIANT& varSrc); + // Assign a const VARIANT* (::VariantCopy handles everything) + + OLEVariant& operator=(const VARIANT* pSrc); + void setByte(sal_uInt8 n) ; + void setInt16(sal_Int16 n) ; + void setInt32(sal_Int32 n) ; + void setFloat(float f) ; + void setDouble(double d) ; + void setDate(DATE d) ; + void setChar(unsigned char a) ; + void setCurrency(double aCur) ; + void setBool(bool b) ; + void setString(const OUString& us) ; + void setNoArg() ; + + void setIDispatch(IDispatch* pDispInterface); + void setNull() ; + void setEmpty() ; + + void setUI1SAFEARRAYPtr(SAFEARRAY* pSafeAr); + void setArray(SAFEARRAY* pSafeArray, VARTYPE vtType); + bool isNull() const ; + bool isEmpty() const ; + + VARTYPE getType() const ; + void ChangeType(VARTYPE vartype, const OLEVariant* pSrc); + + OUString getString() const; + bool getBool() const; + IUnknown* getIUnknown() const; + IDispatch* getIDispatch() const; + sal_uInt8 getByte() const; + sal_Int16 getInt16() const; + sal_Int8 getInt8() const; + sal_Int32 getInt32() const; + sal_uInt32 getUInt32() const; + float getFloat() const; + double getDouble() const; + double getDateAsDouble() const; + CY getCurrency() const; + css::util::Date getDate() const; + css::util::Time getTime() const; + css::util::DateTime getDateTime() const; + css::uno::Sequence<sal_Int8> getByteSequence() const; + SAFEARRAY* getUI1SAFEARRAYPtr() const; + css::uno::Any makeAny() const; + + static VARIANT_BOOL VariantBool(bool bEinBoolean); + + private: + void CHS(); + + void set(double n); + + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AOLEVARIANT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/Aolewrap.hxx b/connectivity/source/inc/ado/Aolewrap.hxx new file mode 100644 index 000000000..ef5c1a859 --- /dev/null +++ b/connectivity/source/inc/ado/Aolewrap.hxx @@ -0,0 +1,225 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AOLEWRAP_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AOLEWRAP_HXX + +#include <osl/diagnose.h> +#include <osl/thread.h> +#include <map> +#include <vector> + +namespace rtl +{ + class OUString; +} +namespace connectivity +{ + namespace ado + { + class OLEVariant; + class WpBase + { + protected: + IDispatch* pIUnknown; + + void setIDispatch(IDispatch* _pIUnknown); + public: + WpBase(); + WpBase(IDispatch* pInt); + //inline + WpBase& operator=(const WpBase& rhs); + WpBase& operator=(IDispatch* rhs); + WpBase(const WpBase& aWrapper); + virtual ~WpBase(); + void clear(); + + + bool IsValid() const; + operator IDispatch*(); + + }; + + // Template class WpOLEBase<class T> + // ================================== + // + // Objects of this class contain a pointer to an interface of the type T. + // The ctors and operator= make sure, that AddRef() and Release() are being + // called adhering to COM conventions. + // An object can also hold no pointer (null pointer), calling IsValid() then + // returns false. + // + // In order to do efficient pass-by-value, this class (as all derived classes) + // is a thin wrapper class, avoiding virtual methods and inlining. + + template<class T> class WpOLEBase : public WpBase + { + protected: + T* pInterface; + + public: + WpOLEBase(T* pInt = nullptr) : WpBase(pInt),pInterface(pInt){} + + + //inline + WpOLEBase<T>& operator=(const WpOLEBase<T>& rhs) + { + WpBase::operator=(rhs); + pInterface = rhs.pInterface; + return *this; + }; + + WpOLEBase<T>& operator=(T* rhs) + { + WpBase::operator=(rhs); + pInterface = rhs.pInterface; + return *this; + } + + WpOLEBase(const WpOLEBase<T>& aWrapper) + : WpBase( aWrapper ) + , pInterface( aWrapper.pInterface ) + { + } + + operator T*() const { return pInterface; } + void setWithOutAddRef(T* _pInterface) + { + pInterface = _pInterface; + WpBase::setIDispatch(_pInterface); + } + }; + + + // Template class WpOLECollection<class Ts, class T, class WrapT> + // =============================================================== + // + // This class (derived from WpOLEBase<Ts>), abstracts away the properties + // common to DAO collections: + // + // They are accessed via an interface Ts (e.g. DAOFields) and can return + // Items of the Type T (actually: with the interface T, e.g. DAOField) + // via get_Item (here GetItem). + // + // This wrapper class does not expose an interface T, however, + // it exposes an object of the class WrapT. This must allow a construction + // by T, preferably it is derived from WpOLEBase<T>. + + template<class Ts, class T, class WrapT> class WpOLECollection : public WpOLEBase<Ts> + { + public: + using WpOLEBase<Ts>::pInterface; + using WpOLEBase<Ts>::IsValid; + // Ctors, operator= + // They only call the superclass + WpOLECollection(Ts* pInt=nullptr):WpOLEBase<Ts>(pInt){} + WpOLECollection(const WpOLECollection& rhs) : WpOLEBase<Ts>(rhs) {} + WpOLECollection& operator=(const WpOLECollection& rhs) + {WpOLEBase<Ts>::operator=(rhs); return *this;}; + + + void Refresh(){pInterface->Refresh();} + + sal_Int32 GetItemCount() const + { + sal_Int32 nCount = 0; + return pInterface ? (SUCCEEDED(pInterface->get_Count(&nCount)) ? nCount : sal_Int32(0)) : sal_Int32(0); + } + + WrapT GetItem(sal_Int32 index) const + { + OSL_ENSURE(index >= 0 && index<GetItemCount(),"Wrong index for field!"); + T* pT = NULL; + WrapT aRet(NULL); + if(SUCCEEDED(pInterface->get_Item(OLEVariant(index), &pT))) + aRet.setWithOutAddRef(pT); + return aRet; + } + + WrapT GetItem(const OLEVariant& index) const + { + T* pT = NULL; + WrapT aRet(NULL); + if(SUCCEEDED(pInterface->get_Item(index, &pT))) + aRet.setWithOutAddRef(pT); + return aRet; + } + + WrapT GetItem(const OUString& sStr) const + { + WrapT aRet(NULL); + T* pT = NULL; + if (FAILED(pInterface->get_Item(OLEVariant(sStr), &pT))) + { +#if OSL_DEBUG_LEVEL > 0 + OString sTemp("Unknown Item: " + OString(sStr.getStr(),sStr.getLength(),osl_getThreadTextEncoding())); + OSL_FAIL(sTemp.getStr()); +#endif + } + else + aRet.setWithOutAddRef(pT); + return aRet; + } + void fillElementNames(::std::vector< OUString>& _rVector) + { + if(IsValid()) + { + Refresh(); + sal_Int32 nCount = GetItemCount(); + _rVector.reserve(nCount); + for(sal_Int32 i=0;i< nCount;++i) + { + WrapT aElement = GetItem(i); + if(aElement.IsValid()) + _rVector.push_back(aElement.get_Name()); + } + } + } + }; + + template<class Ts, class T, class WrapT> class WpOLEAppendCollection: + public WpOLECollection<Ts,T,WrapT> + { + + public: + // Ctors, operator= + // They only call the superclass + using WpOLEBase<Ts>::pInterface; + WpOLEAppendCollection(Ts* pInt=nullptr):WpOLECollection<Ts,T,WrapT>(pInt){} + WpOLEAppendCollection(const WpOLEAppendCollection& rhs) : WpOLECollection<Ts, T, WrapT>(rhs) {} + WpOLEAppendCollection& operator=(const WpOLEAppendCollection& rhs) + {WpOLEBase<Ts>::operator=(rhs); return *this;}; + + + bool Append(const WrapT& aWrapT) + { + return SUCCEEDED(pInterface->Append(OLEVariant(static_cast<T*>(aWrapT)))); + }; + + bool Delete(const OUString& sName) + { + return SUCCEEDED(pInterface->Delete(OLEVariant(sName))); + }; + + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AOLEWRAP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/Awrapado.hxx b/connectivity/source/inc/ado/Awrapado.hxx new file mode 100644 index 000000000..c7817a75b --- /dev/null +++ b/connectivity/source/inc/ado/Awrapado.hxx @@ -0,0 +1,376 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AWRAPADO_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AWRAPADO_HXX + +#include <com/sun/star/beans/PropertyAttribute.hpp> + +// Includes for ADO +#include <oledb.h> +#include <ocidl.h> +#include <adoint.h> +#include <ado/adoimp.hxx> +#include <ado/Aolewrap.hxx> +#include <ado/Aolevariant.hxx> + +namespace connectivity +{ + namespace ado + { + class WpADOConnection; + class WpADOCommand; + class WpADORecordset; + class WpADOField; + class WpADOParameter; + class WpADOError; + class WpADOProperty; + + typedef WpOLEAppendCollection< ADOFields, ADOField, WpADOField> WpADOFields; + typedef WpOLECollection< ADOProperties, ADOProperty, WpADOProperty> WpADOProperties; + + + class WpADOConnection : public WpOLEBase<ADOConnection> + { + friend class WpADOCommand; + public: + + WpADOConnection(ADOConnection* pInt) : WpOLEBase<ADOConnection>(pInt){} + + WpADOConnection(const WpADOConnection& rhs) : WpOLEBase<ADOConnection>(rhs) {} + + WpADOConnection& operator=(const WpADOConnection& rhs) + {WpOLEBase<ADOConnection>::operator=(rhs); return *this;} + + + WpADOProperties get_Properties() const; + + OUString GetConnectionString() const; + bool PutConnectionString(const OUString &aCon) const; + sal_Int32 GetCommandTimeout() const; + void PutCommandTimeout(sal_Int32 nRet); + sal_Int32 GetConnectionTimeout() const ; + void PutConnectionTimeout(sal_Int32 nRet); + + bool Close( ) ; + bool Execute(const OUString& CommandText,OLEVariant& RecordsAffected,long Options, WpADORecordset** ppiRset); + bool BeginTrans(); + bool CommitTrans( ) ; + bool RollbackTrans( ); + bool Open(const OUString& ConnectionString, const OUString& UserID,const OUString& Password,long Options); + bool GetErrors(ADOErrors** pErrors); + + OUString GetDefaultDatabase() const; + bool PutDefaultDatabase(const OUString& _bstr); + + IsolationLevelEnum get_IsolationLevel() const ; + bool put_IsolationLevel(const IsolationLevelEnum& eNum) ; + + sal_Int32 get_Attributes() const; + bool put_Attributes(sal_Int32 nRet); + + CursorLocationEnum get_CursorLocation() const; + bool put_CursorLocation(const CursorLocationEnum &eNum) ; + + ConnectModeEnum get_Mode() const; + bool put_Mode(const ConnectModeEnum &eNum) ; + + OUString get_Provider() const; + bool put_Provider(const OUString& _bstr); + + sal_Int32 get_State() const; + + bool OpenSchema(SchemaEnum eNum,OLEVariant const & Restrictions,OLEVariant const & SchemaID,ADORecordset**pprset); + + OUString get_Version() const; + + // special methods + ADORecordset* getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ); + ADORecordset* getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ); + ADORecordset* getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ); + ADORecordset* getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, bool unique, bool approximate ); + ADORecordset* getTablePrivileges( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& tableNamePattern ); + ADORecordset* getCrossReference( const css::uno::Any& primaryCatalog, + const OUString& primarySchema, + const OUString& primaryTable, + const css::uno::Any& foreignCatalog, + const OUString& foreignSchema, + const OUString& foreignTable); + ADORecordset* getProcedures( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& procedureNamePattern ); + ADORecordset* getProcedureColumns( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& procedureNamePattern, + const OUString& columnNamePattern ); + ADORecordset* getTables( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence< OUString >& types ); + ADORecordset* getColumns( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& tableNamePattern, + const OUString& columnNamePattern ); + ADORecordset* getColumnPrivileges( const css::uno::Any& catalog, + const OUString& schemaPattern, + const OUString& table, + const OUString& columnNamePattern ); + ADORecordset* getTypeInfo(DataTypeEnum _eType = adEmpty ); + }; + + + class WpADOCommand : public WpOLEBase<ADOCommand> + { + public: + WpADOCommand(){} + // Ctors, operator= + // They only call the superclass + WpADOCommand(ADOCommand* pInt) : WpOLEBase<ADOCommand>(pInt){} + + WpADOCommand(const WpADOCommand& rhs) : WpOLEBase<ADOCommand>(rhs) {} + + WpADOCommand& operator=(const WpADOCommand& rhs) + { + WpOLEBase<ADOCommand>::operator=(rhs); return *this;} + + + bool putref_ActiveConnection( WpADOConnection *pCon); + + void put_ActiveConnection(/* [in] */ const OLEVariant& vConn); + void Create(); + sal_Int32 get_State() const; + OUString get_CommandText() const; + bool put_CommandText(const OUString &aCon) ; + sal_Int32 get_CommandTimeout() const; + void put_CommandTimeout(sal_Int32 nRet); + bool get_Prepared() const; + bool put_Prepared(VARIANT_BOOL bPrepared) const; + bool Execute(OLEVariant& RecordsAffected,OLEVariant& Parameters,long Options, ADORecordset** ppiRset); + ADOParameter* CreateParameter(const OUString &_bstr,DataTypeEnum Type,ParameterDirectionEnum Direction,long nSize,const OLEVariant &Value); + + ADOParameters* get_Parameters() const; + bool put_CommandType( /* [in] */ CommandTypeEnum lCmdType); + CommandTypeEnum get_CommandType( ) const ; + // Returns the field's name + OUString GetName() const ; + bool put_Name(const OUString& Name); + bool Cancel(); + }; + + class WpADOError : public WpOLEBase<ADOError> + { + public: + + // Ctors, operator= + // They only call the superclass + WpADOError(ADOError* pInt):WpOLEBase<ADOError>(pInt){} + + WpADOError(const WpADOError& rhs) : WpOLEBase<ADOError>(rhs) {} + + WpADOError& operator=(const WpADOError& rhs) + {WpOLEBase<ADOError>::operator=(rhs); return *this;} + + + OUString GetDescription() const; + OUString GetSource() const ; + sal_Int32 GetNumber() const ; + OUString GetSQLState() const ; + sal_Int32 GetNativeError() const ; + }; + + + class WpADOField : public WpOLEBase<ADOField> + { + // friend class WpADOFields; + public: + + // Ctors, operator= + // They only call the superclass + WpADOField(ADOField* pInt=nullptr):WpOLEBase<ADOField>(pInt){} + WpADOField(const WpADOField& rhs) : WpOLEBase<ADOField>(rhs) {} + + WpADOField& operator=(const WpADOField& rhs) + {WpOLEBase<ADOField>::operator=(rhs); return *this;} + + + WpADOProperties get_Properties(); + sal_Int32 GetActualSize() const ; + sal_Int32 GetAttributes() const ; + sal_Int32 GetStatus() const ; + sal_Int32 GetDefinedSize() const ; + // Returns the field's name + OUString GetName() const ; + DataTypeEnum GetADOType() const ; + void get_Value(OLEVariant& aValVar) const ; + OLEVariant get_Value() const; + bool PutValue(const OLEVariant& aVariant); + sal_Int32 GetPrecision() const ; + sal_Int32 GetNumericScale() const ; + bool AppendChunk(const OLEVariant& Variant); + OLEVariant GetChunk(long Length) const; + void GetChunk(long Length,OLEVariant &aValVar) const; + OLEVariant GetOriginalValue() const; + void GetOriginalValue(OLEVariant &aValVar) const; + OLEVariant GetUnderlyingValue() const; + + void GetUnderlyingValue(OLEVariant &aValVar) const; + + bool PutPrecision(sal_Int8 _prec); + + bool PutNumericScale(sal_Int8 _prec); + + void PutADOType(DataTypeEnum eType) ; + + bool PutDefinedSize(sal_Int32 _nDefSize); + + bool PutAttributes(sal_Int32 _nDefSize); + }; + + + class WpADOProperty: public WpOLEBase<ADOProperty> + { + public: + // Ctors, operator= + // They only call the superclass + WpADOProperty(ADOProperty* pInt=nullptr):WpOLEBase<ADOProperty>(pInt){} + WpADOProperty(const WpADOProperty& rhs) : WpOLEBase<ADOProperty>(rhs) {} + WpADOProperty& operator=(const WpADOProperty& rhs) + {WpOLEBase<ADOProperty>::operator=(rhs); return *this;} + + + OLEVariant GetValue() const; + void GetValue(OLEVariant &aValVar) const; + bool PutValue(const OLEVariant &aValVar) ; + OUString GetName() const ; + DataTypeEnum GetADOType() const ; + sal_Int32 GetAttributes() const ; + bool PutAttributes(sal_Int32 _nDefSize); + }; + + + class WpADORecordset : public WpOLEBase<ADORecordset> + { + + public: + // Ctors, operator= + // They only call the superclass + WpADORecordset(ADORecordset* pInt=nullptr):WpOLEBase<ADORecordset>(pInt){} + WpADORecordset(const WpADORecordset& rhs) : WpOLEBase<ADORecordset>() {operator=(rhs);} + WpADORecordset& operator=(const WpADORecordset& rhs) + { + WpOLEBase<ADORecordset>::operator=(rhs); + return *this; + } + + void Create(); + bool Open( + /* [optional][in] */ VARIANT Source, + /* [optional][in] */ VARIANT ActiveConnection, + /* [defaultvalue][in] */ CursorTypeEnum CursorType, + /* [defaultvalue][in] */ LockTypeEnum LockType, + /* [defaultvalue][in] */ sal_Int32 Options); + LockTypeEnum GetLockType(); + void Close(); + bool Cancel() const; + sal_Int32 get_State( ); + bool Supports( /* [in] */ CursorOptionEnum CursorOptions); + PositionEnum_Param get_AbsolutePosition(); + void GetDataSource(IUnknown** pIUnknown) const ; + void PutRefDataSource(IUnknown* pIUnknown); + void GetBookmark(VARIANT& var); + OLEVariant GetBookmark(); + CompareEnum CompareBookmarks(const OLEVariant& left,const OLEVariant& right); + bool SetBookmark(const OLEVariant &pSafeAr); + WpADOFields GetFields() const; + bool Move(sal_Int32 nRows, VARIANT aBmk); + bool MoveNext(); + bool MovePrevious(); + bool MoveFirst(); + bool MoveLast(); + + bool IsAtBOF() const; + bool IsAtEOF() const; + bool Delete(AffectEnum eNum); + bool AddNew(const OLEVariant &FieldList,const OLEVariant &Values); + bool Update(const OLEVariant &FieldList,const OLEVariant &Values); + bool CancelUpdate(); + WpADOProperties get_Properties() const; + bool NextRecordset(OLEVariant& RecordsAffected,ADORecordset** ppiRset); + bool get_RecordCount(ADO_LONGPTR &_nRet) const; + bool get_MaxRecords(ADO_LONGPTR &_nRet) const; + bool put_MaxRecords(ADO_LONGPTR _nRet); + bool get_CursorType(CursorTypeEnum &_nRet) const; + bool put_CursorType(CursorTypeEnum _nRet); + bool get_LockType(LockTypeEnum &_nRet) const; + bool put_LockType(LockTypeEnum _nRet); + bool get_CacheSize(sal_Int32 &_nRet) const; + bool put_CacheSize(sal_Int32 _nRet); + bool UpdateBatch(AffectEnum AffectRecords); + }; + + + class WpADOParameter:public WpOLEBase<ADOParameter> + { + public: + // Ctors, operator= + // They only call the superclass + WpADOParameter(ADOParameter* pInt):WpOLEBase<ADOParameter>(pInt){} + WpADOParameter(const WpADOParameter& rhs):WpOLEBase<ADOParameter>(rhs){} + WpADOParameter& operator=(const WpADOParameter& rhs) + {WpOLEBase<ADOParameter>::operator=(rhs); return *this;} + + + OUString GetName() const ; + DataTypeEnum GetADOType() const ; + void put_Type(const DataTypeEnum& _eType); + bool put_Size(sal_Int32 _nSize); + sal_Int32 GetAttributes() const ; + sal_Int32 GetPrecision() const ; + sal_Int32 GetNumericScale() const ; + ParameterDirectionEnum get_Direction() const; + void GetValue(OLEVariant& aValVar) const ; + OLEVariant GetValue() const; + bool PutValue(const OLEVariant& aVariant); + bool AppendChunk(const OLEVariant& aVariant); + }; + + class OTools + { + public: + /** putValue set the property value at the ado column + @param _rProps the properties where to set + @param _aPosition which property to set + @param _aValVar the value to set + */ + static void putValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition,const OLEVariant &_aValVar); + + /** getValue returns a specific property value + @param _rProps the properties where to set + @param _aPosition the property + + @return the property value + */ + static OLEVariant getValue(const WpADOProperties& _rProps,const OLEVariant &_aPosition); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_AWRAPADO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/Awrapadox.hxx b/connectivity/source/inc/ado/Awrapadox.hxx new file mode 100644 index 000000000..7a4f3e5a1 --- /dev/null +++ b/connectivity/source/inc/ado/Awrapadox.hxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/beans/PropertyAttribute.hpp> + +#ifndef __User_FWD_DEFINED__ +#define __User_FWD_DEFINED__ +typedef struct _ADOUser User; +#endif + +#ifndef __Group_FWD_DEFINED__ +#define __Group_FWD_DEFINED__ +typedef struct _ADOGroup Group; +#endif + +#ifndef __Column_FWD_DEFINED__ +#define __Column_FWD_DEFINED__ +typedef struct _ADOColumn Column; +#endif + +#ifndef __Index_FWD_DEFINED__ +#define __Index_FWD_DEFINED__ +typedef struct _ADOIndex Index; +#endif + +#ifndef __Key_FWD_DEFINED__ +#define __Key_FWD_DEFINED__ +typedef struct _ADOKey Key; +#endif + +#ifndef __Table_FWD_DEFINED__ +#define __Table_FWD_DEFINED__ +typedef struct _ADOTable Table; +#endif + + +#include <adoint.h> +#include <adoctint.h> + + +#include <ado/Aolewrap.hxx> +#include <ado/Aolevariant.hxx> +#include <ado/adoimp.hxx> +#include <ado/Awrapado.hxx> +#include <ado/WrapColumn.hxx> +#include <ado/WrapIndex.hxx> +#include <ado/WrapKey.hxx> +#include <ado/WrapTable.hxx> +#include <ado/WrapCatalog.hxx> + +namespace connectivity +{ + namespace ado + { + class WpADOView : public WpOLEBase<ADOView> + { + public: + WpADOView(ADOView* pInt=nullptr) : WpOLEBase<ADOView>(pInt){} + WpADOView(const WpADOView& rhs) : WpOLEBase<ADOView>(rhs) {} + + WpADOView& operator=(const WpADOView& rhs) + {WpOLEBase<ADOView>::operator=(rhs); return *this;} + + OUString get_Name() const; + void get_Command(OLEVariant& _rVar) const; + void put_Command(OLEVariant const & _rVar); + }; + + class WpADOGroup : public WpOLEBase<ADOGroup> + { + public: + WpADOGroup(ADOGroup* pInt=nullptr) : WpOLEBase<ADOGroup>(pInt){} + WpADOGroup(const WpADOGroup& rhs) : WpOLEBase<ADOGroup>(rhs) {} + + WpADOGroup& operator=(const WpADOGroup& rhs) + {WpOLEBase<ADOGroup>::operator=(rhs); return *this;} + + void Create(); + + OUString get_Name() const; + void put_Name(const OUString& _rName); + RightsEnum GetPermissions( + /* [in] */ const OLEVariant& Name, + /* [in] */ ObjectTypeEnum ObjectType); + bool SetPermissions( + /* [in] */ const OLEVariant& Name, + /* [in] */ ObjectTypeEnum ObjectType, + /* [in] */ ActionEnum Action, + /* [in] */ RightsEnum Rights); + WpADOUsers get_Users( ); + }; + + class WpADOUser : public WpOLEBase<_ADOUser> + { + public: + WpADOUser(_ADOUser* pInt=nullptr) : WpOLEBase<_ADOUser>(pInt){} + WpADOUser(const WpADOUser& rhs) : WpOLEBase<_ADOUser>(rhs) {} + + WpADOUser& operator=(const WpADOUser& rhs) + {WpOLEBase<_ADOUser>::operator=(rhs); return *this;} + + void Create(); + + OUString get_Name() const; + void put_Name(const OUString& _rName); + bool ChangePassword(const OUString& _rPwd,const OUString& _rNewPwd); + WpADOGroups get_Groups(); + RightsEnum GetPermissions( + /* [in] */ const OLEVariant& Name, + /* [in] */ ObjectTypeEnum ObjectType); + bool SetPermissions( + /* [in] */ const OLEVariant& Name, + /* [in] */ ObjectTypeEnum ObjectType, + /* [in] */ ActionEnum Action, + /* [in] */ RightsEnum Rights); + }; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/WrapCatalog.hxx b/connectivity/source/inc/ado/WrapCatalog.hxx new file mode 100644 index 000000000..3587d5bcd --- /dev/null +++ b/connectivity/source/inc/ado/WrapCatalog.hxx @@ -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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPCATALOG_HXX + +#include <ado/WrapTypeDefs.hxx> + +namespace connectivity +{ + namespace ado + { + class WpADOCatalog : public WpOLEBase<_ADOCatalog> + { + public: + WpADOCatalog(_ADOCatalog* pInt = nullptr) : WpOLEBase<_ADOCatalog>(pInt){} + WpADOCatalog(const WpADOCatalog& rhs) : WpOLEBase<_ADOCatalog>(rhs) {} + + WpADOCatalog& operator=(const WpADOCatalog& rhs) + {WpOLEBase<_ADOCatalog>::operator=(rhs); return *this;} + + OUString GetObjectOwner(const OUString& _rName, ObjectTypeEnum _eNum); + + void putref_ActiveConnection(IDispatch* pCon); + WpADOTables get_Tables(); + WpADOViews get_Views(); + WpADOGroups get_Groups(); + WpADOUsers get_Users(); + ADOProcedures* get_Procedures(); + void Create(); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/WrapColumn.hxx b/connectivity/source/inc/ado/WrapColumn.hxx new file mode 100644 index 000000000..7f3dd3d86 --- /dev/null +++ b/connectivity/source/inc/ado/WrapColumn.hxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPCOLUMN_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPCOLUMN_HXX + +#include <ado/Aolewrap.hxx> + +#include <adoint.h> + +namespace connectivity +{ + namespace ado + { + class WpADOColumn : public WpOLEBase<_ADOColumn> + { + public: + WpADOColumn(_ADOColumn* pInt=nullptr) : WpOLEBase<_ADOColumn>(pInt){} + WpADOColumn(const WpADOColumn& rhs) : WpOLEBase<_ADOColumn>(rhs) {} + + void Create(); + + WpADOColumn& operator=(const WpADOColumn& rhs) + {WpOLEBase<_ADOColumn>::operator=(rhs); return *this;} + + OUString get_Name() const; + OUString get_RelatedColumn() const; + void put_Name(const OUString& _rName); + void put_RelatedColumn(const OUString& _rName); + DataTypeEnum get_Type() const; + void put_Type(const DataTypeEnum& _eNum) ; + sal_Int32 get_Precision() const; + void put_Precision(sal_Int32 _nPre) ; + sal_uInt8 get_NumericScale() const; + void put_NumericScale(sal_Int8 _nScale); + SortOrderEnum get_SortOrder() const; + void put_SortOrder(SortOrderEnum _nScale); + sal_Int32 get_DefinedSize() const; + ColumnAttributesEnum get_Attributes() const; + bool put_Attributes(const ColumnAttributesEnum& _eNum); + WpADOProperties get_Properties() const; + void put_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPCOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/WrapIndex.hxx b/connectivity/source/inc/ado/WrapIndex.hxx new file mode 100644 index 000000000..e60a1249a --- /dev/null +++ b/connectivity/source/inc/ado/WrapIndex.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPINDEX_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPINDEX_HXX + +#include <ado/WrapTypeDefs.hxx> + +namespace connectivity +{ + namespace ado + { + class WpADOIndex : public WpOLEBase<_ADOIndex> + { + public: + WpADOIndex(_ADOIndex* pInt=nullptr) : WpOLEBase<_ADOIndex>(pInt){} + WpADOIndex(const WpADOIndex& rhs) : WpOLEBase<_ADOIndex>(rhs) {} + + WpADOIndex& operator=(const WpADOIndex& rhs) + {WpOLEBase<_ADOIndex>::operator=(rhs); return *this;} + + void Create(); + + OUString get_Name() const; + void put_Name(const OUString& _rName); + bool get_Clustered() const; + void put_Clustered(bool _b); + bool get_Unique() const; + void put_Unique(bool _b); + bool get_PrimaryKey() const; + void put_PrimaryKey(bool _b); + WpADOColumns get_Columns() const; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPINDEX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/WrapKey.hxx b/connectivity/source/inc/ado/WrapKey.hxx new file mode 100644 index 000000000..e5e10a56c --- /dev/null +++ b/connectivity/source/inc/ado/WrapKey.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPKEY_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPKEY_HXX + +#include <ado/WrapTypeDefs.hxx> + +namespace connectivity +{ + namespace ado + { + class WpADOKey : public WpOLEBase<ADOKey> + { + public: + WpADOKey(ADOKey* pInt=nullptr) : WpOLEBase<ADOKey>(pInt){} + WpADOKey(const WpADOKey& rhs) : WpOLEBase<ADOKey>(rhs) {} + + WpADOKey& operator=(const WpADOKey& rhs) + {WpOLEBase<ADOKey>::operator=(rhs); return *this;} + + void Create(); + + OUString get_Name() const; + void put_Name(const OUString& _rName); + KeyTypeEnum get_Type() const; + void put_Type(const KeyTypeEnum& _eNum) ; + OUString get_RelatedTable() const; + void put_RelatedTable(const OUString& _rName); + RuleEnum get_DeleteRule() const; + void put_DeleteRule(const RuleEnum& _eNum) ; + RuleEnum get_UpdateRule() const; + void put_UpdateRule(const RuleEnum& _eNum) ; + WpADOColumns get_Columns() const; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPKEY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/WrapTable.hxx b/connectivity/source/inc/ado/WrapTable.hxx new file mode 100644 index 000000000..b7a1be72e --- /dev/null +++ b/connectivity/source/inc/ado/WrapTable.hxx @@ -0,0 +1,59 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPTABLE_HXX + +#include <ado/WrapTypeDefs.hxx> + +namespace connectivity +{ + namespace ado + { + class WpADOCatalog; + + class WpADOTable : public WpOLEBase<_ADOTable> + { + public: + WpADOTable(_ADOTable* pInt=nullptr) : WpOLEBase<_ADOTable>(pInt){} + WpADOTable(const WpADOTable& rhs) : WpOLEBase<_ADOTable>(rhs) {} + + WpADOTable& operator=(const WpADOTable& rhs) + {WpOLEBase<_ADOTable>::operator=(rhs); return *this;} + + void Create(); + + OUString get_Name() const; + void put_Name(const OUString& _rName); + OUString get_Type() const; + WpADOColumns get_Columns() const; + WpADOIndexes get_Indexes() const; + WpADOKeys get_Keys() const; + WpADOCatalog get_ParentCatalog() const; + WpADOProperties get_Properties() const; + void putref_ParentCatalog(/* [in] */ _ADOCatalog __RPC_FAR *ppvObject); + }; + + + typedef WpOLEAppendCollection<ADOTables, _ADOTable, WpADOTable> WpADOTables; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/WrapTypeDefs.hxx b/connectivity/source/inc/ado/WrapTypeDefs.hxx new file mode 100644 index 000000000..1a76dc5f8 --- /dev/null +++ b/connectivity/source/inc/ado/WrapTypeDefs.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPTYPEDEFS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPTYPEDEFS_HXX + + +namespace connectivity +{ + namespace ado + { + class WpADOTable; + class WpADOKey; + class WpADOIndex; + class WpADOColumn; + class WpADOGroup; + class WpADOView; + class WpADOUser; + + typedef WpOLEAppendCollection<ADOTables, _ADOTable, WpADOTable> WpADOTables; + typedef WpOLEAppendCollection<ADOKeys, ADOKey, WpADOKey> WpADOKeys; + typedef WpOLEAppendCollection<ADOIndexes, _ADOIndex, WpADOIndex> WpADOIndexes; + typedef WpOLEAppendCollection<ADOColumns, _ADOColumn, WpADOColumn> WpADOColumns; + typedef WpOLEAppendCollection<ADOGroups, ADOGroup, WpADOGroup> WpADOGroups; + typedef WpOLEAppendCollection<ADOViews, ADOView, WpADOView> WpADOViews; + typedef WpOLEAppendCollection<ADOUsers, _ADOUser, WpADOUser> WpADOUsers; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_WRAPTYPEDEFS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/ado/adoimp.hxx b/connectivity/source/inc/ado/adoimp.hxx new file mode 100644 index 000000000..8393ca731 --- /dev/null +++ b/connectivity/source/inc/ado/adoimp.hxx @@ -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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADOIMP_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADOIMP_HXX + +#include <com/sun/star/sdbc/SQLException.hpp> + +#include <adoctint.h> + +struct ADOConnection; +namespace connectivity +{ + namespace ado + { + + class WpADOField; + class OLEString; + class ADOS + { + public: + // Also here: Free BSTR with SysFreeString()! + static OLEString& GetKeyStr(); + + static const CLSID CLSID_ADOCATALOG_25; + static const IID IID_ADOCATALOG_25; + + static const CLSID CLSID_ADOCONNECTION_21; + static const IID IID_ADOCONNECTION_21; + + static const CLSID CLSID_ADOCOMMAND_21; + static const IID IID_ADOCOMMAND_21; + + static const CLSID CLSID_ADORECORDSET_21; + static const IID IID_ADORECORDSET_21; + + static const CLSID CLSID_ADOINDEX_25; + static const IID IID_ADOINDEX_25; + + static const CLSID CLSID_ADOCOLUMN_25; + static const IID IID_ADOCOLUMN_25; + + static const CLSID CLSID_ADOKEY_25; + static const IID IID_ADOKEY_25; + + static const CLSID CLSID_ADOTABLE_25; + static const IID IID_ADOTABLE_25; + + static const CLSID CLSID_ADOGROUP_25; + static const IID IID_ADOGROUP_25; + + static const CLSID CLSID_ADOUSER_25; + static const IID IID_ADOUSER_25; + + static const CLSID CLSID_ADOVIEW_25; + static const IID IID_ADOVIEW_25; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static void ThrowException(ADOConnection* _pAdoCon,const css::uno::Reference< css::uno::XInterface >& _xInterface); + static sal_Int32 MapADOType2Jdbc(DataTypeEnum eType); + static DataTypeEnum MapJdbc2ADOType(sal_Int32 _nType,sal_Int32 _nJetEngine); + static bool isJetEngine(sal_Int32 _nEngineType); + + static ObjectTypeEnum mapObjectType2Ado(sal_Int32 objType); + static sal_Int32 mapAdoType2Object(ObjectTypeEnum objType); + static sal_Int32 mapAdoRights2Sdbc(RightsEnum eRights); + static sal_Int32 mapRights2Ado(sal_Int32 nRights); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static WpADOField getField(ADORecordset* _pRecordSet,sal_Int32 _nColumnIndex); + }; + + + } +} + +#define ADO_PROP(ItemName) \ + WpADOProperty aProp(aProps.GetItem(ItemName)); \ + OLEVariant aVar; \ + if(aProp.IsValid()) \ + aVar = aProp.GetValue(); \ + else \ + ADOS::ThrowException(*m_pADOConnection,*this); + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ADO_ADOIMP_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/calc/CCatalog.hxx b/connectivity/source/inc/calc/CCatalog.hxx new file mode 100644 index 000000000..724b5fb12 --- /dev/null +++ b/connectivity/source/inc/calc/CCatalog.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <file/FCatalog.hxx> + +namespace connectivity +{ + namespace calc + { + class OCalcConnection; + class OCalcCatalog : public file::OFileCatalog + { + public: + virtual void refreshTables() override; + + public: + OCalcCatalog(OCalcConnection* _pCon); + }; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/calc/CConnection.hxx b/connectivity/source/inc/calc/CConnection.hxx new file mode 100644 index 000000000..088f47994 --- /dev/null +++ b/connectivity/source/inc/calc/CConnection.hxx @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <memory> +#include <file/FConnection.hxx> +#include <com/sun/star/frame/XDesktop2.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <unotools/closeveto.hxx> + +namespace com::sun::star { + namespace sheet { class XSpreadsheetDocument; } +} + +namespace utl { class CloseVeto; } + + +namespace connectivity +{ + namespace calc + { + class ODriver; + class OCalcConnection : public file::OConnection + { + // the spreadsheet document: + css::uno::Reference< css::sheet::XSpreadsheetDocument > m_xDoc; + OUString m_sPassword; + OUString m_aFileName; + oslInterlockedCount m_nDocCount; + + class CloseVetoButTerminateListener : public cppu::WeakComponentImplHelper<css::frame::XTerminateListener> + { + private: + /// close listener that vetoes so nobody else disposes m_xDoc + std::unique_ptr<utl::CloseVeto> m_pCloseListener; + /// but also listen to XDesktop and if app is terminating anyway, dispose m_xDoc while + /// its still possible to do so properly + css::uno::Reference<css::frame::XDesktop2> m_xDesktop; + osl::Mutex m_aMutex; + public: + CloseVetoButTerminateListener() + : cppu::WeakComponentImplHelper<css::frame::XTerminateListener>(m_aMutex) + { + } + + void start(const css::uno::Reference<css::uno::XInterface>& rCloseable, + const css::uno::Reference<css::frame::XDesktop2>& rDesktop) + { + m_xDesktop = rDesktop; + m_xDesktop->addTerminateListener(this); + m_pCloseListener.reset(new utl::CloseVeto(rCloseable, true)); + } + + void stop() + { + m_pCloseListener.reset(); + if (!m_xDesktop.is()) + return; + m_xDesktop->removeTerminateListener(this); + m_xDesktop.clear(); + } + + // XTerminateListener + virtual void SAL_CALL queryTermination(const css::lang::EventObject& /*rEvent*/) override + { + } + + virtual void SAL_CALL notifyTermination(const css::lang::EventObject& /*rEvent*/) override + { + stop(); + } + + virtual void SAL_CALL disposing() override + { + stop(); + cppu::WeakComponentImplHelperBase::disposing(); + } + + virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override + { + const bool bShutDown = (rEvent.Source == m_xDesktop); + if (bShutDown) + stop(); + } + }; + + rtl::Reference<CloseVetoButTerminateListener> m_xCloseVetoButTerminateListener; + + public: + OCalcConnection(ODriver* _pDriver); + virtual ~OCalcConnection() override; + + virtual void construct(const OUString& _rUrl, + const css::uno::Sequence< css::beans::PropertyValue >& _rInfo ) override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XConnection + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override; + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + + // no interface methods + css::uno::Reference< css::sheet::XSpreadsheetDocument> const & acquireDoc(); + void releaseDoc(); + + class ODocHolder + { + OCalcConnection* m_pConnection; + css::uno::Reference< css::sheet::XSpreadsheetDocument> m_xDoc; + public: + ODocHolder(OCalcConnection* _pConnection) : m_pConnection(_pConnection) + { + m_xDoc = m_pConnection->acquireDoc(); + } + ~ODocHolder() + { + m_xDoc.clear(); + m_pConnection->releaseDoc(); + } + const css::uno::Reference< css::sheet::XSpreadsheetDocument>& getDoc() const { return m_xDoc; } + }; + }; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/calc/CDatabaseMetaData.hxx b/connectivity/source/inc/calc/CDatabaseMetaData.hxx new file mode 100644 index 000000000..a46d09c14 --- /dev/null +++ b/connectivity/source/inc/calc/CDatabaseMetaData.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <component/CDatabaseMetaData.hxx> + +namespace connectivity +{ + namespace calc + { + + //************ Class: java.sql.DatabaseMetaDataDate + + + class OCalcDatabaseMetaData : public component::OComponentDatabaseMetaData + { + virtual OUString SAL_CALL getURL( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + protected: + virtual ~OCalcDatabaseMetaData() override; + public: + OCalcDatabaseMetaData(file::OConnection* _pCon); + }; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/calc/CDriver.hxx b/connectivity/source/inc/calc/CDriver.hxx new file mode 100644 index 000000000..73b2f564c --- /dev/null +++ b/connectivity/source/inc/calc/CDriver.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <file/FDriver.hxx> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +namespace connectivity +{ + namespace calc + { + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > + ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + class ODriver : public file::OFileDriver + { + public: + ODriver(const css::uno::Reference< + css::uno::XComponentContext >& _rxContext) : + file::OFileDriver(_rxContext) {} + + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + OUString SAL_CALL getImplementationName( ) override; + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL + connect( const OUString& url, const css::uno::Sequence< + css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + }; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/calc/CTable.hxx b/connectivity/source/inc/calc/CTable.hxx new file mode 100644 index 000000000..b9835c222 --- /dev/null +++ b/connectivity/source/inc/calc/CTable.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <component/CTable.hxx> +#include <tools/date.hxx> + +namespace com::sun::star::sheet { + class XSpreadsheet; +} + +namespace com::sun::star::util { + class XNumberFormats; +} + + +namespace connectivity +{ + namespace calc + { + typedef component::OComponentTable OCalcTable_BASE; + class OCalcConnection; + + class OCalcTable : public OCalcTable_BASE + { + private: + std::vector<sal_Int32> m_aTypes; // holds all type for columns just to avoid to ask the propertyset + css::uno::Reference< css::sheet::XSpreadsheet > m_xSheet; + OCalcConnection* m_pCalcConnection; + sal_Int32 m_nStartCol; + sal_Int32 m_nStartRow; + sal_Int32 m_nDataCols; + bool m_bHasHeaders; + css::uno::Reference< css::util::XNumberFormats > m_xFormats; + ::Date m_aNullDate; + + void fillColumns(); + + public: + OCalcTable( sdbcx::OCollection* _pTables,OCalcConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description = OUString(), + const OUString& SchemaName = OUString(), + const OUString& CatalogName = OUString() + ); + + virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override; + + virtual void SAL_CALL disposing() override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + void construct() override; + }; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/calc/CTables.hxx b/connectivity/source/inc/calc/CTables.hxx new file mode 100644 index 000000000..65c7135f0 --- /dev/null +++ b/connectivity/source/inc/calc/CTables.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <file/FTables.hxx> + +namespace connectivity +{ + namespace calc + { + typedef file::OTables OCalcTables_BASE; + + class OCalcTables : public OCalcTables_BASE + { + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + public: + OCalcTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : OCalcTables_BASE(_rMetaData,_rParent,_rMutex,_rVector) + {} + }; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/component/CColumns.hxx b/connectivity/source/inc/component/CColumns.hxx new file mode 100644 index 000000000..2a37db2b5 --- /dev/null +++ b/connectivity/source/inc/component/CColumns.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CCOLUMNS_HXX + +#include <file/FColumns.hxx> + +namespace connectivity +{ + namespace component + { + /// Columns implementation for Writer tables and Calc sheets. + class OComponentColumns : public file::OColumns + { + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + public: + OComponentColumns(file::OFileTable* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector + ) : file::OColumns(_pTable,_rMutex,_rVector) + {} + + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/component/CDatabaseMetaData.hxx b/connectivity/source/inc/component/CDatabaseMetaData.hxx new file mode 100644 index 000000000..6006455a3 --- /dev/null +++ b/connectivity/source/inc/component/CDatabaseMetaData.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CDATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CDATABASEMETADATA_HXX + +#include <file/FDatabaseMetaData.hxx> + +namespace connectivity +{ + namespace component + { + + //************ Class: java.sql.DatabaseMetaDataDate + + + class OOO_DLLPUBLIC_FILE OComponentDatabaseMetaData : public file::ODatabaseMetaData + { + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + protected: + virtual ~OComponentDatabaseMetaData() override; + public: + OComponentDatabaseMetaData(file::OConnection* _pCon); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CDATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/component/CPreparedStatement.hxx b/connectivity/source/inc/component/CPreparedStatement.hxx new file mode 100644 index 000000000..30597141a --- /dev/null +++ b/connectivity/source/inc/component/CPreparedStatement.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CPREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CPREPAREDSTATEMENT_HXX + +#include <file/FPreparedStatement.hxx> + +namespace connectivity +{ + namespace component + { + class OConnection; + /// Prepared statement implementation for Writer tables and Calc sheets. + class OOO_DLLPUBLIC_FILE OComponentPreparedStatement : public file::OPreparedStatement + { + protected: + virtual file::OResultSet* createResultSet() override; + public: + OComponentPreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){} + DECLARE_SERVICE_INFO(); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CPREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/component/CResultSet.hxx b/connectivity/source/inc/component/CResultSet.hxx new file mode 100644 index 000000000..e3abc8e78 --- /dev/null +++ b/connectivity/source/inc/component/CResultSet.hxx @@ -0,0 +1,84 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CRESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CRESULTSET_HXX + +#include <file/FResultSet.hxx> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <cppuhelper/implbase2.hxx> + +namespace connectivity +{ + namespace component + { + class OComponentResultSet; + // these typedef's are only necessary for the compiler + typedef ::cppu::ImplHelper2< css::sdbcx::XRowLocate, + css::sdbcx::XDeleteRows> OComponentResultSet_BASE; + typedef file::OResultSet OComponentResultSet_BASE2; + typedef ::comphelper::OPropertyArrayUsageHelper<OComponentResultSet> OComponentResultSet_BASE3; + + + /// ResultSet implementation for Writer tables and Calc sheets. + class OComponentResultSet : public OComponentResultSet_BASE2, + public OComponentResultSet_BASE, + public OComponentResultSet_BASE3 + { + bool m_bBookmarkable; + protected: + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex) override; + public: + DECLARE_SERVICE_INFO(); + + OComponentResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator); + + private: + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // XRowLocate + virtual css::uno::Any SAL_CALL getBookmark( ) override; + virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override; + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override; + virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override; + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override; + virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override; + // XDeleteRows + virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override; + + virtual bool isRowDeleted() const override { return false; } + + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/component/CStatement.hxx b/connectivity/source/inc/component/CStatement.hxx new file mode 100644 index 000000000..d7fc74981 --- /dev/null +++ b/connectivity/source/inc/component/CStatement.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CSTATEMENT_HXX + +#include <file/FStatement.hxx> + +namespace connectivity +{ + namespace component + { + class OConnection; + /// Statement implementation for Writer tables and Calc sheets. + class OOO_DLLPUBLIC_FILE OComponentStatement : public file::OStatement + { + protected: + virtual file::OResultSet* createResultSet() override; + public: + OComponentStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){} + DECLARE_SERVICE_INFO(); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/component/CTable.hxx b/connectivity/source/inc/component/CTable.hxx new file mode 100644 index 000000000..5068f88d5 --- /dev/null +++ b/connectivity/source/inc/component/CTable.hxx @@ -0,0 +1,71 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CTABLE_HXX + +#include <file/FTable.hxx> + +namespace com::sun::star::sheet { + class XSpreadsheet; +} + +namespace com::sun::star::util { + class XNumberFormats; +} + + +namespace connectivity +{ + namespace component + { + typedef file::OFileTable OComponentTable_BASE; + + /// Shared Table base class for Writer tables and Calc sheets. + class OOO_DLLPUBLIC_FILE OComponentTable : public OComponentTable_BASE + { + protected: + sal_Int32 m_nDataRows; + + virtual void FileClose() override; + public: + OComponentTable( sdbcx::OCollection* _pTables,file::OConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description, + const OUString& SchemaName, + const OUString& CatalogName + ); + + virtual void refreshColumns() override; + virtual void refreshIndexes() override; + + virtual sal_Int32 getCurrentLastPos() const override; + virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override; + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_COMPONENT_CTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DCatalog.hxx b/connectivity/source/inc/dbase/DCatalog.hxx new file mode 100644 index 000000000..3ccfed6f6 --- /dev/null +++ b/connectivity/source/inc/dbase/DCatalog.hxx @@ -0,0 +1,42 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCATALOG_HXX + +#include <file/FCatalog.hxx> + +namespace connectivity +{ + namespace dbase + { + class ODbaseConnection; + class ODbaseCatalog : public file::OFileCatalog + { + public: + virtual void refreshTables() override; + + public: + ODbaseCatalog(ODbaseConnection* _pCon); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DColumns.hxx b/connectivity/source/inc/dbase/DColumns.hxx new file mode 100644 index 000000000..c282b43e8 --- /dev/null +++ b/connectivity/source/inc/dbase/DColumns.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCOLUMNS_HXX + +#include <file/FColumns.hxx> + +namespace connectivity +{ + namespace dbase + { + class ODbaseColumns : public file::OColumns + { + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + public: + ODbaseColumns(file::OFileTable* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector + ) : file::OColumns(_pTable,_rMutex,_rVector) + {} + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DConnection.hxx b/connectivity/source/inc/dbase/DConnection.hxx new file mode 100644 index 000000000..f81f7b494 --- /dev/null +++ b/connectivity/source/inc/dbase/DConnection.hxx @@ -0,0 +1,50 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCONNECTION_HXX + +#include <file/FConnection.hxx> + +namespace connectivity +{ + namespace dbase + { + class ODriver; + class ODbaseConnection : public file::OConnection + { + protected: + virtual ~ODbaseConnection() override; + public: + ODbaseConnection(ODriver* _pDriver); + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // XConnection + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override; + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DDatabaseMetaData.hxx b/connectivity/source/inc/dbase/DDatabaseMetaData.hxx new file mode 100644 index 000000000..3424f9c8b --- /dev/null +++ b/connectivity/source/inc/dbase/DDatabaseMetaData.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DDATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DDATABASEMETADATA_HXX + +#include <file/FDatabaseMetaData.hxx> + +namespace connectivity +{ + namespace dbase + { + + //************ Class: java.sql.DatabaseMetaDataDate + + + class ODbaseDatabaseMetaData : public file::ODatabaseMetaData + { + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + + virtual sal_Bool SAL_CALL supportsAlterTableWithAddColumn( ) override; + virtual sal_Bool SAL_CALL supportsAlterTableWithDropColumn( ) override; + + virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override; + virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override; + protected: + virtual ~ODbaseDatabaseMetaData() override; + public: + ODbaseDatabaseMetaData(file::OConnection* _pCon); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DDATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DDriver.hxx b/connectivity/source/inc/dbase/DDriver.hxx new file mode 100644 index 000000000..9378b4c5f --- /dev/null +++ b/connectivity/source/inc/dbase/DDriver.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DDRIVER_HXX + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <connectivity/CommonTools.hxx> +#include <file/FDriver.hxx> + +namespace connectivity +{ + namespace dbase + { + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + class ODriver : public file::OFileDriver + { + public: + ODriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) : file::OFileDriver(_rxContext){} + + // XInterface + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + // static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ) throw (css::uno::RuntimeException); + + OUString SAL_CALL getImplementationName( ) override; + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + }; + } + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DDRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DIndex.hxx b/connectivity/source/inc/dbase/DIndex.hxx new file mode 100644 index 000000000..018c4b915 --- /dev/null +++ b/connectivity/source/inc/dbase/DIndex.hxx @@ -0,0 +1,145 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEX_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEX_HXX + +#include <sdbcx/VIndex.hxx> +#include <dbase/DTable.hxx> +#include <dbase/dindexnode.hxx> + +#define dBASE_III_GROUP "dBase III" + +namespace connectivity +{ + namespace dbase + { + class OIndexIterator; + class ONDXKey; + + typedef sdbcx::OIndex ODbaseIndex_BASE; + + class ODbaseIndex : public ODbaseIndex_BASE + { + friend SvStream& WriteODbaseIndex(SvStream &rStream, ODbaseIndex&); + friend SvStream& operator >> (SvStream &rStream, ODbaseIndex&); + + friend class ONDXNode; + friend class ONDXPage; + friend class ONDXPagePtr; + friend class OIndexIterator; + + public: + + // Header struct - stays in memory + + struct NDXHeader + { + sal_uInt32 db_rootpage; /* Rootpage position */ + sal_uInt32 db_pagecount; /* Page count */ + sal_uInt8 db_free[4]; /* Reserved */ + sal_uInt16 db_keylen; /* Key length */ + sal_uInt16 db_maxkeys; /* Maximum number of keys per page */ + sal_uInt16 db_keytype; /* Type of key: + 0 = Text + 1 = Numerical */ + sal_uInt16 db_keyrec; /* Length of an index record + RecordNumber + keylen */ + sal_uInt8 db_free1[3]; /* Reserved */ + sal_uInt8 db_unique; /* Unique */ + char db_name[488]; /* index_name (field name) */ + }; + + private: + std::unique_ptr<SvStream> m_pFileStream; // Stream to read/write the index + NDXHeader m_aHeader = {}; + std::vector<ONDXPage*> + m_aCollector; // Pool of obsolete pages + ONDXPagePtr m_aRoot, // Root of the B+ tree + m_aCurLeaf; // Current leaf + sal_uInt16 m_nCurNode; // Position of the current node + + sal_uInt32 m_nPageCount, + m_nRootPage; + + ODbaseTable* m_pTable; + bool m_bUseCollector : 1; // Use the Garbage Collector + + OUString getCompletePath() const; + void closeImpl(); + // Closes and kills the index file and throws an error + void impl_killFileAndthrowError_throw(const char* pErrorId, const OUString& _sFile); + protected: + virtual ~ODbaseIndex() override; + public: + ODbaseIndex(ODbaseTable* _pTable); + ODbaseIndex(ODbaseTable* _pTable,const NDXHeader& _aHeader,const OUString& Name); + + void openIndexFile(); + virtual void refreshColumns() override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + const ODbaseTable* getTable() const { return m_pTable; } + const NDXHeader& getHeader() const { return m_aHeader; } + std::unique_ptr<OIndexIterator> createIterator(); + + void SetRootPos(sal_uInt32 nPos) {m_nRootPage = nPos;} + void SetPageCount(sal_uInt32 nCount) {m_nPageCount = nCount;} + + sal_uInt32 GetPageCount() const {return m_nPageCount;} + + sal_uInt16 GetMaxNodes() const {return m_aHeader.db_maxkeys;} + + bool Insert(sal_uInt32 nRec, const ORowSetValue& rValue); + bool Update(sal_uInt32 nRec, const ORowSetValue&, const ORowSetValue&); + bool Delete(sal_uInt32 nRec, const ORowSetValue& rValue); + bool Find(sal_uInt32 nRec, const ORowSetValue& rValue); + + void createINFEntry(); + void CreateImpl(); + void DropImpl(); + + DECLARE_SERVICE_INFO(); + protected: + + ONDXPage* CreatePage(sal_uInt32 nPagePos, ONDXPage* pParent = nullptr, bool bLoad = false); + void Collect(ONDXPage*); + ONDXPagePtr const & getRoot(); + + bool isUnique() const { return m_IsUnique; } + bool UseCollector() const {return m_bUseCollector;} + // Tree operations + void Release(bool bSave = true); + bool ConvertToKey(ONDXKey* rKey, sal_uInt32 nRec, const ORowSetValue& rValue); + }; + + SvStream& WriteODbaseIndex(SvStream &rStream, ODbaseIndex&); + SvStream& operator >> (SvStream &rStream, ODbaseIndex&); + + void ReadHeader(SvStream & rStream, ODbaseIndex::NDXHeader & rHeader); + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEX_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DIndexColumns.hxx b/connectivity/source/inc/dbase/DIndexColumns.hxx new file mode 100644 index 000000000..07aa3d551 --- /dev/null +++ b/connectivity/source/inc/dbase/DIndexColumns.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXCOLUMNS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <dbase/DIndex.hxx> +#include <dbase/DTable.hxx> + +namespace connectivity +{ + namespace dbase + { + class ODbaseIndexColumns : public sdbcx::OCollection + { + ODbaseIndex* m_pIndex; + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + public: + ODbaseIndexColumns( ODbaseIndex* _pIndex, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) + : sdbcx::OCollection(*_pIndex,_pIndex->getTable()->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector) + , m_pIndex(_pIndex) + {} + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXCOLUMNS_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DIndexIter.hxx b/connectivity/source/inc/dbase/DIndexIter.hxx new file mode 100644 index 000000000..1401a0ecc --- /dev/null +++ b/connectivity/source/inc/dbase/DIndexIter.hxx @@ -0,0 +1,71 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXITER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXITER_HXX + +#include <file/fcode.hxx> +#include <dbase/DIndex.hxx> +#include <dbase/dindexnode.hxx> + +namespace connectivity +{ + namespace dbase + { + + // IndexIterator + + class OIndexIterator final + { + file::OBoolOperator* m_pOperator; + const file::OOperand* m_pOperand; + rtl::Reference<ODbaseIndex> m_xIndex; + ONDXPagePtr m_aRoot, + m_aCurLeaf; + sal_uInt16 m_nCurNode; + + sal_uInt32 Find(bool bFirst); + sal_uInt32 GetCompare(bool bFirst); + sal_uInt32 GetLike(bool bFirst); + sal_uInt32 GetNull(bool bFirst); + sal_uInt32 GetNotNull(bool bFirst); + + ONDXKey* GetFirstKey(ONDXPage* pPage, + const file::OOperand& rKey); + ONDXKey* GetNextKey(); + + public: + OIndexIterator(ODbaseIndex* pInd) + :m_pOperator(nullptr) + ,m_pOperand(nullptr) + ,m_xIndex(pInd) + ,m_nCurNode(NODE_NOTFOUND) + { + } + + ~OIndexIterator(); + sal_uInt32 First(); + sal_uInt32 Next(); + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXITER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DIndexes.hxx b/connectivity/source/inc/dbase/DIndexes.hxx new file mode 100644 index 000000000..cccc9347f --- /dev/null +++ b/connectivity/source/inc/dbase/DIndexes.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXES_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <dbase/DTable.hxx> + +namespace connectivity +{ + namespace dbase + { + class ODbaseTable; + + typedef sdbcx::OCollection ODbaseIndexes_BASE; + + class ODbaseIndexes : public ODbaseIndexes_BASE + { + ODbaseTable* m_pTable; + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + public: + ODbaseIndexes(ODbaseTable* _pTable, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : ODbaseIndexes_BASE(*_pTable,_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector) + , m_pTable(_pTable) + {} + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DPreparedStatement.hxx b/connectivity/source/inc/dbase/DPreparedStatement.hxx new file mode 100644 index 000000000..22df7be8e --- /dev/null +++ b/connectivity/source/inc/dbase/DPreparedStatement.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DPREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DPREPAREDSTATEMENT_HXX + +#include <file/FPreparedStatement.hxx> + +namespace connectivity +{ + namespace dbase + { + class OConnection; + class ODbasePreparedStatement : public file::OPreparedStatement + { + protected: + virtual file::OResultSet* createResultSet() override; + public: + ODbasePreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){} + DECLARE_SERVICE_INFO(); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DPREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DResultSet.hxx b/connectivity/source/inc/dbase/DResultSet.hxx new file mode 100644 index 000000000..31a0f6722 --- /dev/null +++ b/connectivity/source/inc/dbase/DResultSet.hxx @@ -0,0 +1,82 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DRESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DRESULTSET_HXX + +#include <file/FResultSet.hxx> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <cppuhelper/implbase2.hxx> + +namespace connectivity +{ + namespace dbase + { + class ODbaseResultSet; + // these typedef's are only necessary for the compiler + typedef ::cppu::ImplHelper2< css::sdbcx::XRowLocate, + css::sdbcx::XDeleteRows> ODbaseResultSet_BASE; + typedef file::OResultSet ODbaseResultSet_BASE2; + typedef ::comphelper::OPropertyArrayUsageHelper<ODbaseResultSet> ODbaseResultSet_BASE3; + + + class ODbaseResultSet : public ODbaseResultSet_BASE2, + public ODbaseResultSet_BASE, + public ODbaseResultSet_BASE3 + { + bool m_bBookmarkable; + protected: + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex) override; + public: + DECLARE_SERVICE_INFO(); + + ODbaseResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // XRowLocate + virtual css::uno::Any SAL_CALL getBookmark( ) override; + virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override; + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override; + virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override; + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override; + virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override; + // XDeleteRows + virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override; + + // own methods + sal_Int32 getCurrentFilePos() const; + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DStatement.hxx b/connectivity/source/inc/dbase/DStatement.hxx new file mode 100644 index 000000000..9c02e2abe --- /dev/null +++ b/connectivity/source/inc/dbase/DStatement.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DSTATEMENT_HXX + +#include <file/FStatement.hxx> + +namespace connectivity +{ + namespace dbase + { + class OConnection; + class ODbaseStatement : public file::OStatement + { + protected: + virtual file::OResultSet* createResultSet() override; + public: + ODbaseStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){} + DECLARE_SERVICE_INFO(); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DTable.hxx b/connectivity/source/inc/dbase/DTable.hxx new file mode 100644 index 000000000..5b9843987 --- /dev/null +++ b/connectivity/source/inc/dbase/DTable.hxx @@ -0,0 +1,198 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DTABLE_HXX + +#include <file/FTable.hxx> +#include <connectivity/CommonTools.hxx> +#include <tools/urlobj.hxx> + + +namespace connectivity +{ + namespace dbase + { + typedef file::OFileTable ODbaseTable_BASE; + class ODbaseConnection; + + class ODbaseTable : public ODbaseTable_BASE + { + // The first byte of a dBase file specifies its type + public: + enum DBFType { dBaseIII = 0x03, + dBaseIV = 0x04, + dBaseV = 0x05, + VisualFoxPro = 0x30, + VisualFoxProAuto = 0x31, // Visual FoxPro with AutoIncrement field + dBaseFS = 0x43, + dBaseFSMemo = 0xB3, + dBaseIIIMemo = 0x83, + dBaseIVMemo = 0x8B, + dBaseIVMemoSQL = 0x8E, + FoxProMemo = 0xF5 + }; + enum DBFMemoType { MemodBaseIII = 0, + MemodBaseIV, + MemoFoxPro + }; + + private: + // sources: https://www.clicketyclick.dk/databases/xbase/format/dbf.html (dBASE III and 5) + // http://www.dbase.com/KnowledgeBase/int/db7_file_fmt.htm (dBASE 7) which is similar at least for this part + struct DBFHeader { // address/pos in trailer + DBFType type; // dBASE/xBASE type, see DBFType 00h + sal_uInt8 dateElems[3]; // Date of last change (YYMMDD) 01h + sal_uInt32 nbRecords; // Number of records 04h + sal_uInt16 headerLength; // 08h + sal_uInt16 recordLength; // Length of 1 record 10h + sal_uInt8 trailer[20]; + // this last field contains these data: + // - reserved:2 bytes:should be filled with 0 12h/0 + // - incomplete transaction:1 byte:dBASE IV 14h/2 + // 00h Transaction ended (or rolled back) + // 01h Transaction started + // - encryptionFlag:1 byte: dBASE IV 15h/3 + // 00h not encrypted + // 01h for encrypted + // - freeRecordThread:4 bytes:reserved for LAN only 16h/4 + // - multiUserdBASE:8 bytes:reserved for multi-user dBASE (dBASE III+) 20h/8 + // - MDXFlag:1 byte:dBASE IV 28h/16 + // 0x01 if a production .MDX file exists for this table + // 0x00 if no .MDX file exists + // - languageDriver:1 byte:codepage (from Foxpro) 29h/17 + // - reserved:2 bytes: should be filled with 0 30h/18 + }; + struct DBFColumn { /* Column descriptors */ + sal_uInt8 db_fnm[11]; /* Field name */ + sal_uInt8 db_typ; /* Field type */ + sal_uInt32 db_adr; /* Field address */ + sal_uInt8 db_flng; /* Field length */ + sal_uInt8 db_dez; /* Decimal places for N */ + sal_uInt8 db_free2[14]; /* Reserved */ + }; + struct DBFMemoHeader + { + DBFMemoType db_typ; /* File type */ + sal_uInt32 db_next; /* Next free block */ + sal_uInt16 db_size; /* Block size: dBase 3 fixed */ + DBFMemoHeader() + : db_typ(MemodBaseIII) + , db_next(0) + , db_size(0) + { + } + }; + + std::vector<sal_Int32> m_aTypes; // holds all types for columns just to avoid to ask the propertyset + std::vector<sal_Int32> m_aPrecisions; // same as above + std::vector<sal_Int32> m_aScales; + std::vector<sal_Int32> m_aRealFieldLengths; + DBFHeader m_aHeader = {}; + DBFMemoHeader m_aMemoHeader; + std::unique_ptr<SvStream> m_pMemoStream; + rtl_TextEncoding m_eEncoding; + + void alterColumn(sal_Int32 index, + const css::uno::Reference< css::beans::XPropertySet>& descriptor , + const css::uno::Reference< css::sdbcx::XDataDescriptorFactory>& xOldColumn ); + void readHeader(); + void fillColumns(); + OUString createTempFile(); + void copyData(ODbaseTable* _pNewTable,sal_Int32 _nPos); + bool CreateFile(const INetURLObject& aFile, bool& bCreateMemo); + bool CreateMemoFile(const INetURLObject& aFile); + bool HasMemoFields() const { return m_aHeader.type > dBaseIV;} + void ReadMemoHeader(); + bool ReadMemo(std::size_t nBlockNo, ORowSetValue& aVariable); + + void WriteMemo(const ORowSetValue& aVariable, std::size_t& rBlockNr); + bool WriteBuffer(); + bool UpdateBuffer(OValueRefVector& rRow, const OValueRefRow& pOrgRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols, bool bForceAllFields); + css::uno::Reference< css::beans::XPropertySet> isUniqueByColumnName(sal_Int32 _nColumnPos); + bool AllocBuffer(); + + void throwInvalidDbaseFormat(); + /// @throws css::sdbc::SQLException + /// @throws css::container::ElementExistException + /// @throws css::uno::RuntimeException + void renameImpl( const OUString& newName ); + void throwInvalidColumnType(const char* pErrorId, const OUString& _sColumnName); + + protected: + virtual void FileClose() override; +// using ::connectivity::sdbcx::OTableDescriptor_BASE::rBHelper; + + public: + virtual void refreshColumns() override; + virtual void refreshIndexes() override; + + public: + ODbaseTable( sdbcx::OCollection* _pTables,ODbaseConnection* _pConnection); + ODbaseTable( sdbcx::OCollection* _pTables,ODbaseConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description = OUString(), + const OUString& SchemaName = OUString(), + const OUString& CatalogName = OUString() + ); + + void construct() override; // can throw any exception + + virtual sal_Int32 getCurrentLastPos() const override; + virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override; + virtual bool fetchRow(OValueRefRow& _rRow,const OSQLColumns& _rCols, bool bRetrieveData) override; + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual void SAL_CALL disposing() override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + // XAlterTable + virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void SAL_CALL alterColumnByIndex( sal_Int32 index, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + // XRename + virtual void SAL_CALL rename( const OUString& newName ) override; + + bool DropImpl(); + bool CreateImpl(); + + + virtual bool InsertRow(OValueRefVector& rRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols) override; + virtual bool DeleteRow(const OSQLColumns& _rCols) override; + virtual bool UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow,const css::uno::Reference< css::container::XIndexAccess>& _xCols) override; + + virtual void addColumn(const css::uno::Reference< css::beans::XPropertySet>& descriptor) override; + virtual void dropColumn(sal_Int32 _nPos) override; + + static OUString getEntry(file::OConnection const * _pConnection,const OUString& _sURL ); + static bool Drop_Static(const OUString& _sUrl, bool _bHasMemoFields, sdbcx::OCollection* _pIndexes ); + + virtual void refreshHeader() override; + + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() const override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/DTables.hxx b/connectivity/source/inc/dbase/DTables.hxx new file mode 100644 index 000000000..fa1957236 --- /dev/null +++ b/connectivity/source/inc/dbase/DTables.hxx @@ -0,0 +1,50 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DTABLES_HXX + +#include <file/FTables.hxx> + +namespace connectivity +{ + namespace dbase + { + typedef file::OTables ODbaseTables_BASE; + + class ODbaseTables : public ODbaseTables_BASE + { + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + public: + ODbaseTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : ODbaseTables_BASE(_rMetaData,_rParent,_rMutex,_rVector) + {} + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DTABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/dbase/dindexnode.hxx b/connectivity/source/inc/dbase/dindexnode.hxx new file mode 100644 index 000000000..70c7b832a --- /dev/null +++ b/connectivity/source/inc/dbase/dindexnode.hxx @@ -0,0 +1,314 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXNODE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXNODE_HXX + +#include <file/fcode.hxx> +#include <connectivity/FValue.hxx> +#include <memory> + +#define NODE_NOTFOUND 0xFFFF +#define DINDEX_PAGE_SIZE 512 + +class SvStream; + +namespace connectivity +{ + namespace dbase + { + + class ONDXNode; + class ODbaseIndex; + + // Index Key + + typedef file::OOperand ONDXKey_BASE; + class ONDXKey : public ONDXKey_BASE + { + friend class ONDXNode; + sal_uInt32 nRecord; /* Record pointer */ + ORowSetValue xValue; /* Key values */ + + public: + ONDXKey(); + ONDXKey(const ORowSetValue& rVal, sal_Int32 eType, sal_uInt32 nRec); + ONDXKey(const OUString& aStr, sal_uInt32 nRec); + ONDXKey(double aVal, sal_uInt32 nRec); + + inline ONDXKey(const ONDXKey& rKey); + + inline ONDXKey& operator= (const ONDXKey& rKey); + virtual void setValue(const ORowSetValue& _rVal) override; + + virtual const ORowSetValue& getValue() const override; + + sal_uInt32 GetRecord() const { return nRecord; } + void setRecord(sal_uInt32 _nRec) { nRecord = _nRec; } + void ResetRecord() { nRecord = 0; } + + bool operator == (const ONDXKey& rKey) const; + bool operator != (const ONDXKey& rKey) const; + bool operator < (const ONDXKey& rKey) const; + bool operator <= (const ONDXKey& rKey) const; + bool operator > (const ONDXKey& rKey) const; + + static bool IsText(sal_Int32 eType); + + private: + int Compare(const ONDXKey& rKey) const; + }; + + + class ONDXPage; + + // Index Page Pointer + // This is ref-count pointer class + class ONDXPagePtr + { + friend SvStream& WriteONDXPagePtr(SvStream &rStream, const ONDXPagePtr&); + friend SvStream& operator >> (SvStream &rStream, ONDXPagePtr&); + + ONDXPage* mpPage; + sal_uInt32 nPagePos; // Position in the index file + + public: + ONDXPagePtr(); + ONDXPagePtr(ONDXPagePtr&& rObj) noexcept; + ONDXPagePtr(ONDXPagePtr const & rRef); + ONDXPagePtr(ONDXPage* pRefPage); + ~ONDXPagePtr(); + void Clear(); + ONDXPagePtr& operator=(ONDXPagePtr const & rRef); + ONDXPagePtr& operator=(ONDXPagePtr && rRef); + bool Is() const { return mpPage != nullptr; } + + ONDXPage * operator ->() const { assert(mpPage != nullptr); return mpPage; } + operator ONDXPage *() const { return mpPage; } + + sal_uInt32 GetPagePos() const {return nPagePos;} + bool HasPage() const {return nPagePos != 0;} + }; + + // Index Page + // This is a ref-counted class, with re-cycling + class ONDXPage + { + friend class ODbaseIndex; + friend class ONDXPagePtr; + + friend SvStream& WriteONDXPage(SvStream &rStream, const ONDXPage&); + friend SvStream& operator >> (SvStream &rStream, ONDXPage&); + + // work around a clang 3.5 optimization bug: if the bNoDelete is *first* + // it mis-compiles "if (--nRefCount == 0)" and never deletes any object + unsigned int nRefCount : 31; + // the only reason this is not bool is because MSVC cannot handle mixed type bitfields + unsigned int bNoDelete : 1; + sal_uInt32 nPagePos; // Position in the index file + bool bModified : 1; + sal_uInt16 nCount; + + ONDXPagePtr aParent, // Parent page + aChild; // Pointer to the right child page + ODbaseIndex& rIndex; + std::unique_ptr<ONDXNode[]> + ppNodes; // Array of nodes + + public: + // Node operations + sal_uInt16 Count() const {return nCount;} + + bool Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft = 0); + bool Insert(sal_uInt16 nIndex, ONDXNode& rNode); + bool Append(ONDXNode& rNode); + void Delete(sal_uInt16); + void Remove(sal_uInt16); + void Release(bool bSave = true); + void ReleaseFull(); + + // Split and merge + ONDXNode Split(ONDXPage& rPage); + void Merge(sal_uInt16 nParentNodePos, const ONDXPagePtr& xPage); + + // Access operators + ONDXNode& operator[] (sal_uInt16 nPos); + const ONDXNode& operator[] (sal_uInt16 nPos) const; + + bool IsRoot() const; + bool IsLeaf() const; + bool IsModified() const; + bool HasParent() const; + + bool IsFull() const; + + sal_uInt32 GetPagePos() const {return nPagePos;} + ONDXPagePtr& GetChild(ODbaseIndex const * pIndex = nullptr); + + // Parent does not need to be reloaded + const ONDXPagePtr& GetParent() const; + ODbaseIndex& GetIndex() {return rIndex;} + const ODbaseIndex& GetIndex() const {return rIndex;} + + // Setting the child, via reference to retain the PagePos + void SetChild(ONDXPagePtr aCh); + void SetParent(ONDXPagePtr aPa); + + sal_uInt16 Search(const ONDXKey& rSearch); + sal_uInt16 Search(const ONDXPage* pPage); + void SearchAndReplace(const ONDXKey& rSearch, ONDXKey const & rReplace); + + protected: + ONDXPage(ODbaseIndex& rIndex, sal_uInt32 nPos, ONDXPage*); + ~ONDXPage(); + + void ReleaseRef(); + void QueryDelete(); + void AddNextRef() + { + assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" ); + ++nRefCount; + } + void AddFirstRef() + { + assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" ); + if( bNoDelete ) + bNoDelete = 0; + ++nRefCount; + } + + void SetModified(bool bMod) {bModified = bMod;} + void SetPagePos(sal_uInt32 nPage) {nPagePos = nPage;} + + bool Find(const ONDXKey&); // Descend recursively + sal_uInt16 FindPos(const ONDXKey& rKey) const; + +#if OSL_DEBUG_LEVEL > 1 + void PrintPage(); +#endif + }; + + SvStream& WriteONDXPagePtr(SvStream &rStream, const ONDXPagePtr&); + SvStream& operator >> (SvStream &rStream, ONDXPagePtr&); + + inline bool ONDXPage::IsRoot() const {return !aParent.Is();} + inline bool ONDXPage::IsLeaf() const {return !aChild.HasPage();} + inline bool ONDXPage::IsModified() const {return bModified;} + inline bool ONDXPage::HasParent() const {return aParent.Is();} + inline const ONDXPagePtr& ONDXPage::GetParent() const {return aParent;} + + inline void ONDXPage::SetParent(ONDXPagePtr aPa = ONDXPagePtr()) + { + aParent = aPa; + } + + inline void ONDXPage::SetChild(ONDXPagePtr aCh = ONDXPagePtr()) + { + aChild = aCh; + if (aChild.Is()) + aChild->SetParent(this); + } + SvStream& operator >> (SvStream &rStream, ONDXPage& rPage); + SvStream& WriteONDXPage(SvStream &rStream, const ONDXPage& rPage); + + + // Index Node + + class ONDXNode + { + friend class ONDXPage; + ONDXPagePtr aChild; /* Next page reference */ + ONDXKey aKey; + + public: + ONDXNode(){} + ONDXNode(const ONDXKey& rKey) + :aKey(rKey) {} + + // Does the node point to a page? + bool HasChild() const {return aChild.HasPage();} + // If an index is provided, we may be able to retrieve the page + ONDXPagePtr& GetChild(ODbaseIndex* pIndex = nullptr, ONDXPage* = nullptr); + + const ONDXKey& GetKey() const { return aKey;} + ONDXKey& GetKey() { return aKey;} + + // Setting the child, via reference to retain the PagePos + void SetChild(ONDXPagePtr aCh = ONDXPagePtr(), ONDXPage* = nullptr); + + void Write(SvStream &rStream, const ONDXPage& rPage) const; + void Read(SvStream &rStream, ODbaseIndex const &); + }; + + inline ONDXKey::ONDXKey(const ONDXKey& rKey) + : ONDXKey_BASE(rKey.getDBType()) + ,nRecord(rKey.nRecord) + ,xValue(rKey.xValue) + { + } + + inline ONDXKey& ONDXKey::operator=(const ONDXKey& rKey) + { + if(&rKey == this) + return *this; + + xValue = rKey.xValue; + nRecord = rKey.nRecord; + m_eDBType = rKey.getDBType(); + return *this; + } + + inline bool ONDXKey::operator == (const ONDXKey& rKey) const + { + if(&rKey == this) + return true; + return Compare(rKey) == 0; + } + inline bool ONDXKey::operator != (const ONDXKey& rKey) const + { + return !operator== (rKey); + } + inline bool ONDXKey::operator < (const ONDXKey& rKey) const + { + return Compare(rKey) < 0; + } + inline bool ONDXKey::operator > (const ONDXKey& rKey) const + { + return Compare(rKey) > 0; + } + inline bool ONDXKey::operator <= (const ONDXKey& rKey) const + { + return !operator > (rKey); + } + + inline void ONDXNode::SetChild(ONDXPagePtr aCh, ONDXPage* pParent) + { + aChild = aCh; + if (aChild.Is()) + aChild->SetParent(pParent); + } + + } + +} + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_DBASE_DINDEXNODE_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FCatalog.hxx b/connectivity/source/inc/file/FCatalog.hxx new file mode 100644 index 000000000..7bdbb7edb --- /dev/null +++ b/connectivity/source/inc/file/FCatalog.hxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCATALOG_HXX + +#include <sdbcx/VCatalog.hxx> + +#include <file/filedllapi.hxx> + +namespace connectivity +{ + namespace file + { + class OConnection; + class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OFileCatalog : + public connectivity::sdbcx::OCatalog + { + protected: + OConnection* m_pConnection; + + /** builds the name which should be used to access the object later on in the collection. + Will only be called in fillNames. + @param _xRow + The current row from the resultset given to fillNames. + */ + virtual OUString buildName( const css::uno::Reference< css::sdbc::XRow >& _xRow) override; + + public: + virtual void refreshTables() override; + virtual void refreshViews() override; + virtual void refreshGroups() override; + virtual void refreshUsers() override; + + public: + OFileCatalog(OConnection* _pCon); + OConnection* getConnection() { return m_pConnection; } + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + // ::cppu::OComponentHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual void SAL_CALL disposing() override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FColumns.hxx b/connectivity/source/inc/file/FColumns.hxx new file mode 100644 index 000000000..57fa6f65c --- /dev/null +++ b/connectivity/source/inc/file/FColumns.hxx @@ -0,0 +1,51 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCOLUMNS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <file/FTable.hxx> +#include <file/filedllapi.hxx> + +namespace connectivity +{ + namespace file + { + class OOO_DLLPUBLIC_FILE OColumns : public sdbcx::OCollection + { + protected: + OFileTable* m_pTable; + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + public: + OColumns( OFileTable* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector + ) : sdbcx::OCollection(*_pTable,_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector) + ,m_pTable(_pTable) + {} + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FConnection.hxx b/connectivity/source/inc/file/FConnection.hxx new file mode 100644 index 000000000..8511f2771 --- /dev/null +++ b/connectivity/source/inc/file/FConnection.hxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCONNECTION_HXX + +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <connectivity/CommonTools.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <TConnection.hxx> +#include <file/filedllapi.hxx> + +namespace connectivity +{ + namespace file + { + class ODatabaseMetaData; + class OFileDriver; + + class OOO_DLLPUBLIC_FILE OConnection : public connectivity::OMetaConnection + { + protected: + + // Data attributes + + css::uno::WeakReference< css::sdbcx::XTablesSupplier> m_xCatalog; + + OUString m_aFilenameExtension; + OFileDriver* m_pDriver; // Pointer to the owning + // driver object + css::uno::Reference< css::ucb::XDynamicResultSet > m_xDir; // directory + css::uno::Reference< css::ucb::XContent> m_xContent; + + bool m_bAutoCommit; + bool m_bReadOnly; + bool m_bShowDeleted; + bool m_bCaseSensitiveExtension; + bool m_bCheckSQL92; + bool m_bDefaultTextEncoding; + + + void throwUrlNotValid(const OUString & _rsUrl,const OUString & _rsMessage); + + virtual ~OConnection() override; + public: + + OConnection(OFileDriver* _pDriver); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + /// @throws css::uno::DeploymentException + virtual void construct(const OUString& _rUrl, const css::uno::Sequence< css::beans::PropertyValue >& _rInfo ); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override final; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + // XCloseable + virtual void SAL_CALL close( ) override final; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + //XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + // no interface methods + css::uno::Reference< css::ucb::XDynamicResultSet > getDir() const; + const css::uno::Reference< css::ucb::XContent>& getContent() const { return m_xContent; } + // create a catalog or return the catalog already created + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog(); + + bool matchesExtension( const OUString& _rExt ) const; + + const OUString& getExtension() const { return m_aFilenameExtension; } + bool isCaseSensitiveExtension() const { return m_bCaseSensitiveExtension; } + OFileDriver* getDriver() const { return m_pDriver; } + bool showDeleted() const { return m_bShowDeleted; } + bool isCheckEnabled() const { return m_bCheckSQL92; } + bool isTextEncodingDefaulted() const { return m_bDefaultTextEncoding; } + + public: + struct GrantAccess + { + friend class ODatabaseMetaData; + private: + GrantAccess() { } + }; + + void setCaseSensitiveExtension( bool _bIsCS, GrantAccess ) { m_bCaseSensitiveExtension = _bIsCS; } + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FDatabaseMetaData.hxx b/connectivity/source/inc/file/FDatabaseMetaData.hxx new file mode 100644 index 000000000..6f726cf74 --- /dev/null +++ b/connectivity/source/inc/file/FDatabaseMetaData.hxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDATABASEMETADATA_HXX + +#include <TDatabaseMetaDataBase.hxx> +#include <file/FConnection.hxx> +#include <file/filedllapi.hxx> + +namespace connectivity +{ + namespace file + { + + //************ Class: ODatabaseMetaData + + + class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE ODatabaseMetaData : + public ODatabaseMetaDataBase + { + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + // cached database information + virtual OUString impl_getIdentifierQuoteString_throw( ) override; + virtual bool impl_isCatalogAtStart_throw( ) override; + virtual OUString impl_getCatalogSeparator_throw( ) override; + virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override; + virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ; + virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override; + virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ; + virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override; + virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override; + virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override; + virtual sal_Int32 impl_getMaxStatements_throw( ) override; + virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override; + virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override; + protected: + OConnection* m_pConnection; // I need the native class not only the interface + virtual ~ODatabaseMetaData() override; + public: + + ODatabaseMetaData(OConnection* _pCon); + // XDatabaseMetaData + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FDateFunctions.hxx b/connectivity/source/inc/file/FDateFunctions.hxx new file mode 100644 index 000000000..e2fa6965d --- /dev/null +++ b/connectivity/source/inc/file/FDateFunctions.hxx @@ -0,0 +1,233 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDATEFUNCTIONS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDATEFUNCTIONS_HXX + +#include <file/fcode.hxx> + +namespace connectivity +{ + namespace file + { + /** DAYOFWEEK(date) + Returns the weekday index for date (1 = Sunday, 2 = Monday, ... 7 = Saturday). These index values correspond to the ODBC standard. + + > SELECT DAYOFWEEK('1998-02-03'); + -> 3 + */ + class OOp_DayOfWeek : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** DAYOFMONTH(date) + Returns the day of the month for date, in the range 1 to 31: + + > SELECT DAYOFMONTH('1998-02-03'); + -> 3 + */ + class OOp_DayOfMonth : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** DAYOFYEAR(date) + Returns the day of the year for date, in the range 1 to 366: + + > SELECT DAYOFYEAR('1998-02-03'); + -> 34 + + */ + class OOp_DayOfYear : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** MONTH(date) + Returns the month for date, in the range 1 to 12: + + > SELECT MONTH('1998-02-03'); + -> 2 + */ + class OOp_Month : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** DAYNAME(date) + Returns the name of the weekday for date: + + > SELECT DAYNAME('1998-02-05'); + -> 'Thursday' + + */ + class OOp_DayName : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** MONTHNAME(date) + Returns the name of the month for date: + + > SELECT MONTHNAME('1998-02-05'); + -> 'February' + + */ + class OOp_MonthName : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** QUARTER(date) + Returns the quarter of the year for date, in the range 1 to 4: + + > SELECT QUARTER('98-04-01'); + -> 2 + + */ + class OOp_Quarter : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** WEEK(date) + WEEK(date,first) + With a single argument, returns the week for date, in the range 0 to 53 (yes, there may be the beginnings of a week 53), for locations where Sunday is the first day of the week. The two-argument form of WEEK() allows you to specify whether the week starts on Sunday or Monday and whether the return value should be in the range 0-53 or 1-52. Here is a table for how the second argument works: + Value Meaning + 0 Week starts on Sunday and return value is in range 0-53 + 1 Week starts on Monday and return value is in range 0-53 + 2 Week starts on Sunday and return value is in range 1-53 + 3 Week starts on Monday and return value is in range 1-53 (ISO 8601) + + > SELECT WEEK('1998-02-20'); + -> 7 + > SELECT WEEK('1998-02-20',0); + -> 7 + > SELECT WEEK('1998-02-20',1); + -> 8 + > SELECT WEEK('1998-12-31',1); + -> 53 + + */ + class OOp_Week : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** YEAR(date) + Returns the year for date, in the range 1000 to 9999: + + > SELECT YEAR('98-02-03'); + -> 1998 + */ + class OOp_Year : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** HOUR(time) + Returns the hour for time, in the range 0 to 23: + + > SELECT HOUR('10:05:03'); + -> 10 + */ + class OOp_Hour : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** MINUTE(time) + Returns the minute for time, in the range 0 to 59: + + > SELECT MINUTE('98-02-03 10:05:03'); + -> 5 + + */ + class OOp_Minute : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** SECOND(time) + Returns the second for time, in the range 0 to 59: + + > SELECT SECOND('10:05:03'); + -> 3 + */ + class OOp_Second : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** CURDATE() + CURRENT_DATE + Returns today's date as a value in 'YYYY-MM-DD' or YYYYMMDD format, depending on whether the function is used in a string or numeric context: + + > SELECT CURDATE(); + -> '1997-12-15' + */ + class OOp_CurDate : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** CURTIME() + CURRENT_TIME + Returns the current time as a value in 'HH:MM:SS' or HHMMSS format, depending on whether the function is used in a string or numeric context: + + > SELECT CURTIME(); + -> '23:50:26' + */ + class OOp_CurTime : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** NOW() + Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether the function is used in a string or numeric context: + + > SELECT NOW(); + -> '1997-12-15 23:50:26' + */ + class OOp_Now : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDATEFUNCTIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FDriver.hxx b/connectivity/source/inc/file/FDriver.hxx new file mode 100644 index 000000000..efff20274 --- /dev/null +++ b/connectivity/source/inc/file/FDriver.hxx @@ -0,0 +1,82 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDRIVER_HXX + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <cppuhelper/compbase.hxx> +#include <connectivity/CommonTools.hxx> +#include <file/filedllapi.hxx> + +namespace connectivity +{ + namespace file + { + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver, + css::lang::XServiceInfo, + css::sdbcx::XDataDefinitionSupplier> ODriver_BASE; + + class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OFileDriver : public ODriver_BASE + { + protected: + ::osl::Mutex m_aMutex; + + connectivity::OWeakRefArray m_xConnections; // vector containing a list + // of all the Connection objects + // for this Driver + css::uno::Reference< css::uno::XComponentContext > m_xContext; + public: + OFileDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + /// @throws css::uno::DeploymentException + static OUString getImplementationName_Static( ); + /// @throws css::uno::DeploymentException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + + // XDataDefinitionSupplier + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + const css::uno::Reference< css::uno::XComponentContext >& getComponentContext() const { return m_xContext; } + }; + } + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FDRIVER_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FNumericFunctions.hxx b/connectivity/source/inc/file/FNumericFunctions.hxx new file mode 100644 index 000000000..3f143c658 --- /dev/null +++ b/connectivity/source/inc/file/FNumericFunctions.hxx @@ -0,0 +1,367 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FNUMERICFUNCTIONS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FNUMERICFUNCTIONS_HXX + +#include <file/fcode.hxx> + +namespace connectivity +{ + namespace file + { + /** ABS(X) + Returns the absolute value of X: + + > SELECT ABS(2); + -> 2 + > SELECT ABS(-32); + -> 32 + + */ + class OOp_Abs : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** SIGN(X) + Returns the sign of the argument as -1, 0, or 1, depending on whether X is negative, zero, or positive: + + > SELECT SIGN(-32); + -> -1 + > SELECT SIGN(0); + -> 0 + > SELECT SIGN(234); + -> 1 + + */ + class OOp_Sign : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** MOD(N,M) + % + Modulo (like the % operator in C). Returns the remainder of N divided by M: + + > SELECT MOD(234, 10); + -> 4 + > SELECT 253 % 7; + -> 1 + > SELECT MOD(29,9); + -> 2 + > SELECT 29 MOD 9; + -> 2 + */ + class OOp_Mod : public OBinaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override; + }; + + /** FLOOR(X) + Returns the largest integer value not greater than X: + + > SELECT FLOOR(1.23); + -> 1 + > SELECT FLOOR(-1.23); + -> -2 + + */ + class OOp_Floor : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** CEILING(X) + Returns the smallest integer value not less than X: + + > SELECT CEILING(1.23); + -> 2 + > SELECT CEILING(-1.23); + -> -1 + + */ + class OOp_Ceiling : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** ROUND(X) + ROUND(X,D) + Returns the argument X, rounded to the nearest integer. With two arguments rounded to a number to D decimals. + + > SELECT ROUND(-1.23); + -> -1 + > SELECT ROUND(-1.58); + -> -2 + > SELECT ROUND(1.58); + -> 2 + > SELECT ROUND(1.298, 1); + -> 1.3 + > SELECT ROUND(1.298, 0); + -> 1 + > SELECT ROUND(23.298, -1); + -> 20 + */ + class OOp_Round : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** EXP(X) + Returns the value of e (the base of natural logarithms) raised to the power of X: + + > SELECT EXP(2); + -> 7.389056 + > SELECT EXP(-2); + -> 0.135335 + */ + class OOp_Exp : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** LN(X) + Returns the natural logarithm of X: + + > SELECT LN(2); + -> 0.693147 + > SELECT LN(-2); + -> NULL + + */ + class OOp_Ln : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** LOG(X) + LOG(B,X) + If called with one parameter, this function returns the natural logarithm of X: + + > SELECT LOG(2); + -> 0.693147 + > SELECT LOG(-2); + -> NULL + + If called with two parameters, this function returns the logarithm of X for an arbitrary base B: + + > SELECT LOG(2,65536); + -> 16.000000 + > SELECT LOG(1,100); + -> NULL + */ + class OOp_Log : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** LOG10(X) + Returns the base-10 logarithm of X: + + > SELECT LOG10(2); + -> 0.301030 + > SELECT LOG10(100); + -> 2.000000 + > SELECT LOG10(-100); + -> NULL + */ + class OOp_Log10 : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** POWER(X,Y) + Returns the value of X raised to the power of Y: + + > SELECT POW(2,2); + -> 4.000000 + > SELECT POW(2,-2); + -> 0.250000 + */ + class OOp_Pow : public OBinaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override; + }; + + /** SQRT(X) + Returns the non-negative square root of X: + + > SELECT SQRT(4); + -> 2.000000 + > SELECT SQRT(20); + -> 4.472136 + */ + class OOp_Sqrt : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** PI() + Returns the value of PI. The default shown number of decimals is 5, but internally uses the full double precision for PI. + + > SELECT PI(); + -> 3.141593 + > SELECT PI()+0.000000000000000000; + -> 3.141592653589793238 + + */ + class OOp_Pi : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** COS(X) + Returns the cosine of X, where X is given in radians: + + > SELECT COS(PI()); + -> -1.000000 + */ + class OOp_Cos : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** SIN(X) + Returns the sine of X, where X is given in radians: + + > SELECT SIN(PI()); + -> 0.000000 + + */ + class OOp_Sin : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + /** TAN(X) + Returns the tangent of X, where X is given in radians: + + > SELECT TAN(PI()+1); + -> 1.557408 + */ + class OOp_Tan : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** ACOS(X) + Returns the arc cosine of X, that is, the value whose cosine is X. Returns NULL if X is not in the range -1 to 1: + + > SELECT ACOS(1); + -> 0.000000 + > SELECT ACOS(1.0001); + -> NULL + > SELECT ACOS(0); + -> 1.570796 + */ + class OOp_ACos : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** ASIN(X) + Returns the arc sine of X, that is, the value whose sine is X. Returns NULL if X is not in the range -1 to 1: + + > SELECT ASIN(0.2); + -> 0.201358 + > SELECT ASIN('foo'); + -> 0.000000 + */ + class OOp_ASin : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** ATAN(X) + Returns the arc tangent of X, that is, the value whose tangent is X: + + > SELECT ATAN(2); + -> 1.107149 + > SELECT ATAN(-2); + -> -1.107149 + */ + class OOp_ATan : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** ATAN2(Y,X) + Returns the arc tangent of the two variables X and Y. It is similar to calculating the arc tangent of Y / X, except that the signs of both arguments are used to determine the quadrant of the result: + + > SELECT ATAN2(-2,2); + -> -0.785398 + > SELECT ATAN2(PI(),0); + -> 1.570796 + + */ + class OOp_ATan2 : public OBinaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override; + }; + + /** DEGREES(X) + Returns the argument X, converted from radians to degrees: + + > SELECT DEGREES(PI()); + -> 180.000000 + */ + class OOp_Degrees : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** RADIANS(X) + Returns the argument X, converted from degrees to radians: + + > SELECT RADIANS(90); + -> 1.570796 + + */ + class OOp_Radians : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FNUMERICFUNCTIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FPreparedStatement.hxx b/connectivity/source/inc/file/FPreparedStatement.hxx new file mode 100644 index 000000000..31002f6f1 --- /dev/null +++ b/connectivity/source/inc/file/FPreparedStatement.hxx @@ -0,0 +1,125 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FPREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FPREPAREDSTATEMENT_HXX + +#include <file/filedllapi.hxx> +#include <file/FStatement.hxx> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <file/FResultSet.hxx> + +namespace connectivity +{ + namespace file + { + + class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OPreparedStatement : public OStatement_BASE2, + public css::sdbc::XPreparedStatement, + public css::sdbc::XParameters, + public css::sdbc::XResultSetMetaDataSupplier, + public css::lang::XServiceInfo + + { + protected: + + // Data attributes + + OValueRefRow m_aParameterRow; + css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData; + + ::rtl::Reference<connectivity::OSQLColumns> m_xParamColumns; // the parameter columns + + // factory method for resultset's + virtual OResultSet* createResultSet() override; + ::rtl::Reference< OResultSet > makeResultSet(); + void initResultSet(OResultSet*); + + void checkAndResizeParameters(sal_Int32 parameterIndex); + void setParameter(sal_Int32 parameterIndex, const ORowSetValue& x); + + sal_uInt32 AddParameter(connectivity::OSQLParseNode const * pParameter, + const css::uno::Reference< css::beans::XPropertySet>& _xCol); + void scanParameter(OSQLParseNode* pParseNode,std::vector< OSQLParseNode*>& _rParaNodes); + void describeColumn(OSQLParseNode const * _pParameter, OSQLParseNode const * _pNode, const OSQLTable& _xTable); + void describeParameter(); + + virtual void parseParamterElem(const OUString& _sColumnName,OSQLParseNode* pRow_Value_Constructor_Elem) override; + virtual void initializeResultSet(OResultSet* _pResult) override; + + virtual ~OPreparedStatement() override; + public: + DECLARE_SERVICE_INFO(); + // a Constructor, that is needed for when Returning the Object is needed: + OPreparedStatement( OConnection* _pConnection); + + virtual void construct(const OUString& sql) override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + virtual sal_Bool SAL_CALL execute( ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FPREPAREDSTATEMENT_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FResultSet.hxx b/connectivity/source/inc/file/FResultSet.hxx new file mode 100644 index 000000000..6cb42da8e --- /dev/null +++ b/connectivity/source/inc/file/FResultSet.hxx @@ -0,0 +1,308 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FRESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FRESULTSET_HXX + +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <comphelper/proparrhlp.hxx> +#include <file/FStatement.hxx> +#include <connectivity/CommonTools.hxx> +#include <comphelper/propertycontainer.hxx> +#include <file/fanalyzer.hxx> +#include <file/FTable.hxx> +#include <file/filedllapi.hxx> +#include <TSortIndex.hxx> +#include <TSkipDeletedSet.hxx> +#include <com/sun/star/lang/XEventListener.hpp> + +namespace connectivity +{ + namespace file + { + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate, + css::lang::XServiceInfo, + css::lang::XEventListener, + css::lang::XUnoTunnel> OResultSet_BASE; + + class OOO_DLLPUBLIC_FILE OResultSet : + public cppu::BaseMutex, + public ::connectivity::IResultSetHelper, + public OResultSet_BASE, + public ::comphelper::OPropertyContainer, + public ::comphelper::OPropertyArrayUsageHelper<OResultSet> + { + + protected: + std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time + + std::vector<sal_Int32> m_aOrderbyColumnNumber; + std::vector<TAscendingOrder> m_aOrderbyAscending; + + OValueRefRow m_aSelectRow; + OValueRefRow m_aRow; + OValueRefRow m_aEvaluateRow; // contains all values of a row + OValueRefRow m_aInsertRow; // needed for insert by cursor + ORefAssignValues m_aAssignValues; // needed for insert,update and parameters + // to compare with the restrictions + OSkipDeletedSet m_aSkipDeletedSet; + + ::rtl::Reference<OKeySet> m_pFileSet; + OKeySet::iterator m_aFileSetIter; + + + std::unique_ptr<OSortIndex> m_pSortIndex; + ::rtl::Reference<connectivity::OSQLColumns> m_xColumns; // this are the select columns + rtl::Reference<OFileTable> m_pTable; + connectivity::OSQLParseNode* m_pParseTree; + + OSQLAnalyzer* m_pSQLAnalyzer; + connectivity::OSQLParseTreeIterator& m_aSQLIterator; + + sal_Int32 m_nFetchSize; + sal_Int32 m_nResultSetType; + sal_Int32 m_nFetchDirection; + sal_Int32 m_nResultSetConcurrency; + + css::uno::Reference< css::uno::XInterface> m_xStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData; + css::uno::Reference< css::container::XNameAccess> m_xColNames; // table columns + css::uno::Reference< css::container::XIndexAccess> m_xColsIdx; // table columns + + + sal_Int32 m_nRowPos; + sal_Int32 m_nFilePos; + sal_Int32 m_nLastVisitedPos; + sal_Int32 m_nRowCountResult; + sal_Int32 m_nColumnCount; + bool m_bWasNull; + bool m_bInserted; // true when moveToInsertRow was called + // set to false when cursor moved or cancel + bool m_bRowUpdated; + bool m_bRowInserted; + bool m_bRowDeleted; + bool m_bShowDeleted; + bool m_bIsCount; + + static void initializeRow(OValueRefRow& _rRow,sal_Int32 _nColumnCount); + void construct(); + //sal_Bool evaluate(); + + bool ExecuteRow(IResultSetHelper::Movement eFirstCursorPosition, + sal_Int32 nOffset = 1, + bool bEvaluate = true, + bool bRetrieveData = true); + + std::unique_ptr<OKeyValue> GetOrderbyKeyValue(OValueRefRow const & _rRow); + bool IsSorted() const { return !m_aOrderbyColumnNumber.empty() && m_aOrderbyColumnNumber[0] >= 0;} + + // return true when the select statement is "select count(*) from table" + bool isCount() const { return m_bIsCount; } + /// @throws css::sdbc::SQLException + void checkIndex(sal_Int32 columnIndex ); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + const ORowSetValue& getValue(sal_Int32 columnIndex); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void updateValue(sal_Int32 columnIndex,const ORowSetValue& x ); + // clear insert row + void clearInsertRow(); + void sortRows(); + protected: + + using OResultSet_BASE::rBHelper; + + bool Move(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, bool bRetrieveData); + virtual bool fillIndexValues(const css::uno::Reference< css::sdbcx::XColumnsSupplier> &_xIndex); + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual ~OResultSet() override; + public: + DECLARE_SERVICE_INFO(); + // a Constructor, that is needed for when Returning the Object is needed: + OResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator); + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override final; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + //XEventlistener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // special methods + inline sal_Int32 mapColumn(sal_Int32 column); + void OpenImpl(); + void doTableSpecials(const OSQLTable& _xTable); + + sal_Int32 getRowCountResult() const { return m_nRowCountResult; } + void setEvaluationRow(const OValueRefRow& _aRow) { m_aEvaluateRow = _aRow; } + void setAssignValues(const ORefAssignValues& _aAssignValues) { m_aAssignValues = _aAssignValues; } + void setBindingRow(const OValueRefRow& _aRow) { m_aRow = _aRow; } + void setSelectRow(const OValueRefRow& _rRow) + { + m_aSelectRow = _rRow; + m_nColumnCount = m_aSelectRow->size(); + } + void setColumnMapping(const std::vector<sal_Int32>& _aColumnMapping) { m_aColMapping = _aColumnMapping; } + void setSqlAnalyzer(OSQLAnalyzer* _pSQLAnalyzer) { m_pSQLAnalyzer = _pSQLAnalyzer; } + + void setOrderByColumns(const std::vector<sal_Int32>& _aColumnOrderBy) { m_aOrderbyColumnNumber = _aColumnOrderBy; } + void setOrderByAscending(const std::vector<TAscendingOrder>& _aOrderbyAsc) { m_aOrderbyAscending = _aOrderbyAsc; } + void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;} + + static void setBoundedColumns(const OValueRefRow& _rRow, + const OValueRefRow& _rSelectRow, + const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns, + const css::uno::Reference< css::container::XIndexAccess>& _xNames, + bool _bSetColumnMapping, + const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData, + std::vector<sal_Int32>& _rColMapping); + + // IResultSetHelper + virtual bool move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) override; + virtual sal_Int32 getDriverPos() const override; + virtual bool isRowDeleted() const override; + }; + + inline sal_Int32 OResultSet::mapColumn(sal_Int32 column) + { + sal_Int32 map = column; + + OSL_ENSURE(column > 0, "file::OResultSet::mapColumn: invalid column index!"); + // the first column (index 0) is for convenience only. The first real select column is number 1. + if ((column > 0) && (column < static_cast<sal_Int32>(m_aColMapping.size()))) + map = m_aColMapping[column]; + + return map; + } + } +} +#endif // _CONNECTIVITY_FILE_ORESULTSET_HXX_ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FResultSetMetaData.hxx b/connectivity/source/inc/file/FResultSetMetaData.hxx new file mode 100644 index 000000000..9ba77bc29 --- /dev/null +++ b/connectivity/source/inc/file/FResultSetMetaData.hxx @@ -0,0 +1,81 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FRESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FRESULTSETMETADATA_HXX + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include <connectivity/CommonTools.hxx> +#include <rtl/ref.hxx> + +namespace connectivity +{ + namespace file + { + class OFileTable; + + //************ Class: ResultSetMetaData + + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE; + + class OResultSetMetaData : + public OResultSetMetaData_BASE + { + OUString m_aTableName; + ::rtl::Reference<connectivity::OSQLColumns> m_xColumns; + OFileTable* m_pTable; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void checkColumnIndex(sal_Int32 column); + protected: + virtual ~OResultSetMetaData() override; + public: + // a Constructor, that is needed for when Returning the Object is needed: + OResultSetMetaData(const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,const OUString& _aTableName,OFileTable* _pTable); + + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FRESULTSETMETADATA_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FStatement.hxx b/connectivity/source/inc/file/FStatement.hxx new file mode 100644 index 000000000..a5e61a2dd --- /dev/null +++ b/connectivity/source/inc/file/FStatement.hxx @@ -0,0 +1,200 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FSTATEMENT_HXX + +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <comphelper/proparrhlp.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/implbase2.hxx> +#include <cppuhelper/basemutex.hxx> +#include <connectivity/CommonTools.hxx> +#include <connectivity/sqlparse.hxx> +#include <file/FConnection.hxx> +#include <file/filedllapi.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <comphelper/propertycontainer.hxx> +#include <file/fanalyzer.hxx> +#include <TSortIndex.hxx> + +namespace connectivity +{ + namespace file + { + class OResultSet; + class OFileTable; + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier, + css::util::XCancellable, + css::sdbc::XCloseable> OStatement_BASE; + + + //************ Class: java.sql.Statement + + class OOO_DLLPUBLIC_FILE OStatement_Base : + public cppu::BaseMutex, + public OStatement_BASE, + public ::comphelper::OPropertyContainer, + public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base> + + { + protected: + std::vector<sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time + std::vector<sal_Int32> m_aParameterIndexes; // maps the parameter index to column index + std::vector<sal_Int32> m_aOrderbyColumnNumber; + std::vector<TAscendingOrder> m_aOrderbyAscending; + + css::sdbc::SQLWarning m_aLastWarning; + css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created + css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xDBMetaData; + css::uno::Reference< css::container::XNameAccess> m_xColNames; // table columns // for this Statement + + + connectivity::OSQLParser m_aParser; + connectivity::OSQLParseTreeIterator m_aSQLIterator; + + rtl::Reference<OConnection> m_pConnection;// The owning Connection object + connectivity::OSQLParseNode* m_pParseTree; + std::unique_ptr<OSQLAnalyzer> m_pSQLAnalyzer; //the sql analyzer used by the resultset + + rtl::Reference<OFileTable> m_pTable; // the current table + OValueRefRow m_aSelectRow; + OValueRefRow m_aRow; + OValueRefRow m_aEvaluateRow; // contains all values of a row + ORefAssignValues m_aAssignValues; // needed for insert,update and parameters + // to compare with the restrictions + + OUString m_aCursorName; + sal_Int32 m_nMaxFieldSize; + sal_Int32 m_nMaxRows; + sal_Int32 m_nQueryTimeOut; + sal_Int32 m_nFetchSize; + sal_Int32 m_nResultSetType; + sal_Int32 m_nFetchDirection; + sal_Int32 m_nResultSetConcurrency; + bool m_bEscapeProcessing; + + protected: + // initialize the column index map (mapping select columns to table columns) + void createColumnMapping(); + // searches the statement for sort criteria + void anylizeSQL(); + void setOrderbyColumn( connectivity::OSQLParseNode const * pColumnRef, + connectivity::OSQLParseNode const * pAscendingDescending); + + virtual void initializeResultSet(OResultSet* _pResult); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void closeResultSet(); + + void disposeResultSet(); + void GetAssignValues(); + void SetAssignValue(const OUString& aColumnName, + const OUString& aValue, + bool bSetNull = false, + sal_uInt32 nParameter=SQL_NO_PARAMETER); + void ParseAssignValues( const std::vector< OUString>& aColumnNameList, + connectivity::OSQLParseNode* pRow_Value_Constructor_Elem, sal_Int32 nIndex); + + virtual void parseParamterElem(const OUString& _sColumnName,OSQLParseNode* pRow_Value_Constructor_Elem); + // factory method for resultset's + virtual OResultSet* createResultSet() = 0; + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual ~OStatement_Base() override; + public: + connectivity::OSQLParseNode* getParseTree() const { return m_pParseTree;} + + OStatement_Base(OConnection* _pConnection ); + + OConnection* getOwnConnection() const { return m_pConnection.get(); } + + using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + virtual void construct(const OUString& sql); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + // virtual void SAL_CALL release() throw(css::uno::RuntimeException) = 0; + virtual void SAL_CALL acquire() throw() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + }; + + class OOO_DLLPUBLIC_FILE OStatement_BASE2 : public OStatement_Base + + { + public: + OStatement_BASE2(OConnection* _pConnection ) : OStatement_Base(_pConnection ) {} + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual void SAL_CALL release() throw() override; + }; + + typedef ::cppu::ImplHelper2< css::sdbc::XStatement,css::lang::XServiceInfo > OStatement_XStatement; + class OOO_DLLPUBLIC_FILE OStatement : + public OStatement_BASE2, + public OStatement_XStatement + { + protected: + // factory method for resultset's + virtual OResultSet* createResultSet() override; + public: + // a Constructor, that is needed for when Returning the Object is needed: + OStatement( OConnection* _pConnection) : OStatement_BASE2( _pConnection){} + DECLARE_SERVICE_INFO(); + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ; + virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ; + virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FStringFunctions.hxx b/connectivity/source/inc/file/FStringFunctions.hxx new file mode 100644 index 000000000..8d2ea1cef --- /dev/null +++ b/connectivity/source/inc/file/FStringFunctions.hxx @@ -0,0 +1,274 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FSTRINGFUNCTIONS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FSTRINGFUNCTIONS_HXX + +#include <file/fcode.hxx> + +namespace connectivity +{ + namespace file + { + /** UCASE(str) + UPPER(str) + Returns the string str with all characters changed to uppercase according to the current character set mapping (the default is ISO-8859-1 Latin1): + + > SELECT UCASE('Hej'); + -> 'HEJ' + + */ + class OOp_Upper : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** LCASE(str) + LOWER(str) + Returns the string str with all characters changed to lowercase according to the current character set mapping (the default is ISO-8859-1 Latin1): + + > SELECT LCASE('QUADRATICALLY'); + -> 'quadratically' + + */ + class OOp_Lower : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** ASCII(str) + Returns the ASCII code value of the leftmost character of the string str. Returns 0 if str is the empty string. Returns NULL if str is NULL: + + > SELECT ASCII('2'); + -> 50 + > SELECT ASCII(2); + -> 50 + > SELECT ASCII('dx'); + -> 100 + + */ + class OOp_Ascii : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** LENGTH(str) + OCTET_LENGTH(str) + CHAR_LENGTH(str) + CHARACTER_LENGTH(str) + Returns the length of the string str: + + > SELECT LENGTH('text'); + -> 4 + > SELECT OCTET_LENGTH('text'); + -> 4 + + */ + class OOp_CharLength : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** CHAR(N,...) + CHAR() interprets the arguments as integers and returns a string consisting of the characters given by the ASCII code values of those integers. NULL values are skipped: + + > SELECT CHAR(ascii('t'),ascii('e'),ascii('s'),ascii('t')); + -> 'test' + > SELECT CHAR(77,77.3,'77.3'); + -> 'MMM' + + */ + class OOp_Char : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** CONCAT(str1,str2,...) + Returns the string that results from concatenating the arguments. Returns NULL if any argument is NULL. May have more than 2 arguments. A numeric argument is converted to the equivalent string form: + + > SELECT CONCAT('OO', 'o', 'OO'); + -> 'OOoOO' + > SELECT CONCAT('OO', NULL, 'OO'); + -> NULL + > SELECT CONCAT(14.3); + -> '14.3' + + */ + class OOp_Concat : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** LOCATE(substr,str) + POSITION(substr IN str) + Returns the position of the first occurrence of substring substr in string str. Returns 0 if substr is not in str: + + > SELECT LOCATE('bar', 'foobarbar'); + -> 4 + > SELECT LOCATE('xbar', 'foobar'); + -> 0 + LOCATE(substr,str,pos) + Returns the position of the first occurrence of substring substr in string str, starting at position pos. Returns 0 if substr is not in str: + + > SELECT LOCATE('bar', 'foobarbar',5); + -> 7 + + */ + class OOp_Locate : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** SUBSTRING(str,pos) + SUBSTRING(str FROM pos) + Returns a substring from string str starting at position pos: + + > SELECT SUBSTRING('Quadratically',5); + -> 'ratically' + > SELECT SUBSTRING('foobarbar' FROM 4); + -> 'barbar' + SUBSTRING(str,pos,len) + SUBSTRING(str FROM pos FOR len) + Returns a substring len characters long from string str, starting at position pos. The variant form that uses FROM is SQL-92 syntax: + + > SELECT SUBSTRING('Quadratically',5,6); + -> 'ratica' + + */ + class OOp_SubString : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** LTRIM(str) + Returns the string str with leading space characters removed: + + > SELECT LTRIM(' barbar'); + -> 'barbar' + + */ + class OOp_LTrim : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** RTRIM(str) + Returns the string str with trailing space characters removed: + + > SELECT RTRIM('barbar '); + -> 'barbar' + + */ + class OOp_RTrim : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** SPACE(N) + Returns a string consisting of N space characters: + + > SELECT SPACE(6); + -> ' ' + + */ + class OOp_Space : public OUnaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs) const override; + }; + + /** REPLACE(str,from_str,to_str) + Returns the string str with all occurrences of the string from_str replaced by the string to_str: + + > SELECT REPLACE('www.OOo.com', 'w', 'Ww'); + -> 'WwWwWw.OOo.com' + + */ + class OOp_Replace : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** REPEAT(str,count) + Returns a string consisting of the string str repeated count times. If count <= 0, returns an empty string. Returns NULL if str or count are NULL: + + > SELECT REPEAT('OOo', 3); + -> 'OOoOOoOOo' + + */ + class OOp_Repeat : public OBinaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override; + }; + + /** INSERT(str,pos,len,newstr) + Returns the string str, with the substring beginning at position pos and len characters long replaced by the string newstr: + + > SELECT INSERT('Quadratic', 3, 4, 'What'); + -> 'QuWhattic' + + */ + class OOp_Insert : public ONthOperator + { + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const override; + }; + + /** LEFT(str,len) + Returns the leftmost len characters from the string str: + + > SELECT LEFT('foobarbar', 5); + -> 'fooba' + + */ + class OOp_Left : public OBinaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override; + }; + + /** RIGHT(str,len) + Returns the rightmost len characters from the string str: + + > SELECT RIGHT('foobarbar', 4); + -> 'rbar' + */ + class OOp_Right : public OBinaryOperator + { + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const override; + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FSTRINGFUNCTIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FTable.hxx b/connectivity/source/inc/file/FTable.hxx new file mode 100644 index 000000000..68d6efb45 --- /dev/null +++ b/connectivity/source/inc/file/FTable.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FTABLE_HXX + +#include <connectivity/sdbcx/VTable.hxx> +#include <file/FConnection.hxx> +#include <file/filedllapi.hxx> +#include <tools/stream.hxx> +#include <connectivity/FValue.hxx> +#include <TResultSetHelper.hxx> + +namespace connectivity +{ + namespace file + { + typedef connectivity::sdbcx::OTable OTable_TYPEDEF; + + class OOO_DLLPUBLIC_FILE OFileTable : public OTable_TYPEDEF + { + protected: + OConnection* m_pConnection; + std::unique_ptr<SvStream> m_pFileStream; + ::rtl::Reference<OSQLColumns> m_aColumns; + sal_Int32 m_nFilePos; // current IResultSetHelper::Movement + std::unique_ptr<sal_uInt8[]> m_pBuffer; + sal_uInt16 m_nBufferSize; // size of the ReadBuffer, if pBuffer != NULL + bool m_bWriteable; // svstream can't say if we are writeable + // so we have to + + virtual void FileClose(); + virtual ~OFileTable( ) override; + public: + virtual void refreshColumns() override; + virtual void refreshKeys() override; + virtual void refreshIndexes() override; + public: + OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection); + OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description, + const OUString& SchemaName, + const OUString& CatalogName + ); + + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + + OConnection* getConnection() const { return m_pConnection;} + virtual sal_Int32 getCurrentLastPos() const {return -1;} + + virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) = 0; + virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) = 0; + + const ::rtl::Reference<OSQLColumns>& getTableColumns() const {return m_aColumns;} + virtual bool InsertRow(OValueRefVector& rRow, const css::uno::Reference< css::container::XIndexAccess>& _xCols); + virtual bool DeleteRow(const OSQLColumns& _rCols); + virtual bool UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow,const css::uno::Reference< css::container::XIndexAccess>& _xCols); + virtual void addColumn(const css::uno::Reference< css::beans::XPropertySet>& descriptor); + virtual void dropColumn(sal_Int32 _nPos); + // refresh the header of file based tables to see changes done by someone + virtual void refreshHeader(); + + OUString SAL_CALL getName() override { return m_Name; } + + const OUString& getSchema() const { return m_SchemaName; } + bool isReadOnly() const { return !m_bWriteable; } + // m_pFileStream && !m_pFileStream->IsWritable(); } + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + + sal_Int32 getFilePos() const { return m_nFilePos; } + + public: + // helper + + // creates a stream using ::utl::UcbStreamHelper::CreateStream, but the error is simplified + // (NULL or non-NULL is returned) + static std::unique_ptr<SvStream> createStream_simpleError( const OUString& _rFileName, StreamMode _eOpenMode); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/FTables.hxx b/connectivity/source/inc/file/FTables.hxx new file mode 100644 index 000000000..bbc787b57 --- /dev/null +++ b/connectivity/source/inc/file/FTables.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FTABLES_HXX + +#include <file/filedllapi.hxx> +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> + +namespace connectivity +{ + namespace file + { + class OOO_DLLPUBLIC_FILE SAL_NO_VTABLE OTables : + public sdbcx::OCollection + { + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + public: + OTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent,_rMetaData->supportsMixedCaseQuotedIdentifiers(),_rMutex,_rVector) + {} + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FTABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/fanalyzer.hxx b/connectivity/source/inc/file/fanalyzer.hxx new file mode 100644 index 000000000..9fa5d7f45 --- /dev/null +++ b/connectivity/source/inc/file/fanalyzer.hxx @@ -0,0 +1,74 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FANALYZER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FANALYZER_HXX + +#include <file/fcomp.hxx> + +namespace connectivity +{ + namespace file + { + class OConnection; + class OSQLAnalyzer final + { + typedef std::pair< ::rtl::Reference<OPredicateCompiler>,::rtl::Reference<OPredicateInterpreter> > TPredicates; + + std::vector< TPredicates > m_aSelectionEvaluations; + ::rtl::Reference<OPredicateCompiler> m_aCompiler; + ::rtl::Reference<OPredicateInterpreter> m_aInterpreter; + OConnection* m_pConnection; + + mutable bool m_bHasSelectionCode; + mutable bool m_bSelectionFirstTime; + + static void bindRow(OCodeList& rCodeList,const OValueRefRow& _pRow); + + public: + OSQLAnalyzer(OConnection* _pConnection); + ~OSQLAnalyzer(); + + OConnection* getConnection() const { return m_pConnection; } + void bindEvaluationRow(OValueRefRow const & _pRow); // Bind an evaluation row to the restriction + /** bind the select columns if they contain a function which needs a row value + @param _pRow the result row + */ + void bindSelectRow(const OValueRefRow& _pRow); + + /** binds the row to parameter for the restrictions + @param _pRow the parameter row + */ + void bindParameterRow(OValueRefRow const & _pRow); + + void dispose(); + void start(OSQLParseNode const * pSQLParseNode); + bool hasRestriction() const; + bool hasFunctions() const; + bool evaluateRestriction() { return m_aInterpreter->start(); } + void setSelectionEvaluationResult(OValueRefRow const & _pRow,const std::vector<sal_Int32>& _rColumnMapping); + void setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols); + static OOperandAttr* createOperandAttr(sal_Int32 _nPos, + const css::uno::Reference< css::beans::XPropertySet>& _xCol); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FANALYZER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/fcode.hxx b/connectivity/source/inc/file/fcode.hxx new file mode 100644 index 000000000..6a6feb412 --- /dev/null +++ b/connectivity/source/inc/file/fcode.hxx @@ -0,0 +1,333 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCODE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCODE_HXX + +#include <connectivity/sqliterator.hxx> +#include <com/sun/star/sdbc/DataType.hpp> +#include <connectivity/FValue.hxx> +#include <file/filedllapi.hxx> + +#include <stack> + +namespace connectivity +{ + class OSQLParseNode; + namespace file + { + + class OOperand; + typedef std::stack<OOperand*> OCodeStack; + + class OOO_DLLPUBLIC_FILE OCode + { + public: + //virtual dtor to allow this to be the root of the class hierarchy + virtual ~OCode(); + //but that disables the default move ctor + OCode(OCode&&) = default; + //but that disables the rest of default ctors + OCode(const OCode&) = default; + OCode() = default; + //and same issue for the assignment operators + OCode& operator=(const OCode&) = default; + OCode& operator=(OCode&&) = default; + }; + + + // operands that the parsetree generate + class OOO_DLLPUBLIC_FILE OOperand : public OCode + { + protected: + sal_Int32 m_eDBType; + + OOperand(sal_Int32 _rType) : m_eDBType(_rType){} + OOperand() : m_eDBType(css::sdbc::DataType::OTHER){} + + public: + virtual const ORowSetValue& getValue() const = 0; + virtual void setValue(const ORowSetValue& _rVal) = 0; + + sal_Int32 getDBType() const {return m_eDBType;} + inline bool isValid() const; + + }; + + class OOperandRow : public OOperand + { + sal_uInt16 m_nRowPos; + OValueRefRow m_pRow; + + protected: + OOperandRow(sal_uInt16 _nPos, sal_Int32 _rType); + public: + virtual const ORowSetValue& getValue() const override; + virtual void setValue(const ORowSetValue& _rVal) override; + void bindValue(const OValueRefRow& _pRow); // Bind to the value that the operand represents + + }; + + // Attributes from a result row + class OOperandAttr : public OOperandRow + { + public: + OOperandAttr(sal_uInt16 _nPos, + const css::uno::Reference< css::beans::XPropertySet>& _xColumn); + + }; + + // Parameter for a predicate + class OOperandParam : public OOperandRow + { + public: + OOperandParam(connectivity::OSQLParseNode const * pNode, sal_Int32 _nPos); + }; + + // Value operands + class OOperandValue : public OOperand + { + protected: + ORowSetValue m_aValue; + + protected: + OOperandValue(){} + OOperandValue(const ORowSetValue& _rVar, sal_Int32 eDbType) + : OOperand(eDbType) + , m_aValue(_rVar) + {} + + OOperandValue(sal_Int32 eDbType) :OOperand(eDbType){} + public: + virtual const ORowSetValue& getValue() const override; + virtual void setValue(const ORowSetValue& _rVal) override; + + }; + + + // Constants + class OOperandConst : public OOperandValue + { + public: + OOperandConst(const connectivity::OSQLParseNode& rColumnRef, const OUString& aStrValue); + + }; + + + // Result operands + class OOperandResult : public OOperandValue + { + protected: + OOperandResult(sal_Int32 eDbType) + :OOperandValue(eDbType) {} + public: + OOperandResult(const ORowSetValue& _rVar) + :OOperandValue(_rVar, _rVar.getTypeKind()) {} + }; + + + class OOperandResultBOOL : public OOperandResult + { + public: + OOperandResultBOOL(bool bResult) : OOperandResult(css::sdbc::DataType::BIT) + { + m_aValue = bResult ? 1.0 : 0.0; + m_aValue.setBound(true); + } + }; + + class OOperandResultNUM : public OOperandResult + { + public: + OOperandResultNUM(double fNum) : OOperandResult(css::sdbc::DataType::DOUBLE) + { + m_aValue = fNum; + m_aValue.setBound(true); + } + }; + + /** special stop operand + is appended when a list of arguments ends + */ + class OStopOperand : public OOperandValue + { + public: + OStopOperand(){} + }; + + // Operators + class OOO_DLLPUBLIC_FILE OOperator : public OCode + { + public: + virtual void Exec(OCodeStack&) = 0; + }; + + + // Boolean operators + class OOO_DLLPUBLIC_FILE OBoolOperator : public OOperator + { + public: + virtual void Exec(OCodeStack&) override; + virtual bool operate(const OOperand*, const OOperand*) const; + }; + + class OOp_NOT : public OBoolOperator + { + public: + + protected: + virtual void Exec(OCodeStack&) override; + virtual bool operate(const OOperand*, const OOperand*) const override; + }; + + class OOp_AND : public OBoolOperator + { + public: + + protected: + virtual bool operate(const OOperand*, const OOperand*) const override; + }; + + class OOp_OR : public OBoolOperator + { + public: + protected: + virtual bool operate(const OOperand*, const OOperand*) const override; + }; + + class OOO_DLLPUBLIC_FILE OOp_ISNULL : public OBoolOperator + { + public: + public: + virtual void Exec(OCodeStack&) override; + virtual bool operate(const OOperand*, const OOperand*) const override; + }; + + class OOO_DLLPUBLIC_FILE OOp_ISNOTNULL : public OOp_ISNULL + { + public: + virtual bool operate(const OOperand*, const OOperand*) const override; + }; + + class OOO_DLLPUBLIC_FILE OOp_LIKE : public OBoolOperator + { + const sal_Unicode cEscape; + + public: + OOp_LIKE(const sal_Unicode cEsc):cEscape(cEsc){}; + + virtual bool operate(const OOperand*, const OOperand*) const override; + }; + + class OOp_NOTLIKE : public OOp_LIKE + { + public: + public: + OOp_NOTLIKE(const sal_Unicode cEsc):OOp_LIKE(cEsc){}; + + virtual bool operate(const OOperand*, const OOperand*) const override; + }; + + class OOO_DLLPUBLIC_FILE OOp_COMPARE : public OBoolOperator + { + sal_Int32 aPredicateType; + + public: + OOp_COMPARE(sal_Int32 aPType) + :aPredicateType(aPType) {} + + sal_Int32 getPredicateType() const { return aPredicateType; } + virtual bool operate(const OOperand*, const OOperand*) const override; + }; + + // Numerical operators + class ONumOperator : public OOperator + { + public: + virtual void Exec(OCodeStack&) override; + + + protected: + virtual double operate(const double& fLeft,const double& fRight) const = 0; + }; + + class OOp_ADD : public ONumOperator + { + protected: + virtual double operate(const double& fLeft,const double& fRight) const override; + }; + + class OOp_SUB : public ONumOperator + { + protected: + virtual double operate(const double& fLeft,const double& fRight) const override; + }; + + class OOp_MUL : public ONumOperator + { + protected: + virtual double operate(const double& fLeft,const double& fRight) const override; + }; + + class OOp_DIV : public ONumOperator + { + protected: + virtual double operate(const double& fLeft,const double& fRight) const override; + }; + + inline bool OOperand::isValid() const + { + return getValue().getDouble() != 0.0; + } + + // Operator + class ONthOperator : public OOperator + { + public: + virtual void Exec(OCodeStack&) override; + + + protected: + virtual ORowSetValue operate(const std::vector<ORowSetValue>& lhs) const = 0; + }; + + class OBinaryOperator : public OOperator + { + public: + virtual void Exec(OCodeStack&) override; + + + protected: + virtual ORowSetValue operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const = 0; + }; + + class OUnaryOperator : public OOperator + { + public: + virtual void Exec(OCodeStack&) override; + virtual ORowSetValue operate(const ORowSetValue& lhs) const = 0; + + + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCODE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/fcomp.hxx b/connectivity/source/inc/file/fcomp.hxx new file mode 100644 index 000000000..f43b05374 --- /dev/null +++ b/connectivity/source/inc/file/fcomp.hxx @@ -0,0 +1,112 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCOMP_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCOMP_HXX + +#include <file/fcode.hxx> + +namespace connectivity +{ + class OSQLParseNode; + namespace file + { + class OCode; + class OOperand; + class OSQLAnalyzer; + typedef std::vector<std::unique_ptr<OCode>> OCodeList; + + class OPredicateCompiler final : public ::salhelper::SimpleReferenceObject + { + friend class OPredicateInterpreter; + friend class OSQLAnalyzer; + + OCodeList m_aCodeList; + css::uno::Reference< css::container::XNameAccess> m_orgColumns; // in filecurs this are the filecolumns + OSQLAnalyzer* m_pAnalyzer; + sal_Int32 m_nParamCounter; + public: + OPredicateCompiler(OSQLAnalyzer* pAnalyzer); + + virtual ~OPredicateCompiler() override; + + void dispose(); + + void start(connectivity::OSQLParseNode const * pSQLParseNode); + OOperand* execute(connectivity::OSQLParseNode const * pPredicateNode); + + void Clean(); + bool isClean() const {return m_aCodeList.empty();} + bool hasCode() const {return !isClean();} + void setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols) { m_orgColumns = rCols; } + const css::uno::Reference< css::container::XNameAccess>& getOrigColumns() const { return m_orgColumns; } + private: + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void execute_COMPARE(connectivity::OSQLParseNode const * pPredicateNode); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void execute_LIKE(connectivity::OSQLParseNode const * pPredicateNode); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void execute_BETWEEN(connectivity::OSQLParseNode const * pPredicateNode); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void execute_ISNULL(connectivity::OSQLParseNode const * pPredicateNode); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OOperand* execute_Operand(connectivity::OSQLParseNode const * pPredicateNode); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void execute_Fold(OSQLParseNode const * pPredicateNode); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void executeFunction(OSQLParseNode const * pPredicateNode); + }; + + + class OPredicateInterpreter : + public ::salhelper::SimpleReferenceObject + { + OCodeStack m_aStack; + ::rtl::Reference<OPredicateCompiler> m_rCompiler; + + public: + OPredicateInterpreter(const ::rtl::Reference<OPredicateCompiler>& rComp) : m_rCompiler(rComp){} + virtual ~OPredicateInterpreter() override; + + bool evaluate(OCodeList& rCodeList); + void evaluateSelection(OCodeList& rCodeList, ORowSetValueDecoratorRef const & _rVal); + + bool start() + { + return evaluate(m_rCompiler->m_aCodeList); + } + + void startSelection(ORowSetValueDecoratorRef const & _rVal) + { + evaluateSelection(m_rCompiler->m_aCodeList,_rVal); + } + + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FCOMP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/filedllapi.hxx b/connectivity/source/inc/file/filedllapi.hxx new file mode 100644 index 000000000..7bc8ed0ce --- /dev/null +++ b/connectivity/source/inc/file/filedllapi.hxx @@ -0,0 +1,35 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FILEDLLAPI_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_FILEDLLAPI_HXX + +#include <sal/config.h> + +#include <sal/types.h> + +#if defined OOO_DLLIMPLEMENTATION_FILE +#define OOO_DLLPUBLIC_FILE SAL_DLLPUBLIC_EXPORT +#else +#define OOO_DLLPUBLIC_FILE SAL_DLLPUBLIC_IMPORT +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/file/quotedstring.hxx b/connectivity/source/inc/file/quotedstring.hxx new file mode 100644 index 000000000..8d80d15f0 --- /dev/null +++ b/connectivity/source/inc/file/quotedstring.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_QUOTEDSTRING_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_QUOTEDSTRING_HXX + +#include <rtl/ustring.hxx> +#include <file/filedllapi.hxx> + +namespace connectivity +{ + + // Derived from String, overriding GetToken/GetTokenCount methods + // Especially true for the flat file format: Strings can be quoted + + class OOO_DLLPUBLIC_FILE QuotedTokenizedString + { + OUString m_sString; + public: + QuotedTokenizedString() {} + + sal_Int32 GetTokenCount( sal_Unicode cTok , sal_Unicode cStrDel ) const; + OUString GetTokenSpecial(sal_Int32& nStartPos, sal_Unicode cTok, sal_Unicode cStrDel = '\0') const; + OUString& GetString() { return m_sString; } + void SetString(const OUString& aStr) { m_sString = aStr;} + sal_Int32 Len() const { return m_sString.getLength(); } + operator OUString&() { return m_sString; } + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FILE_QUOTEDSTRING_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/ECatalog.hxx b/connectivity/source/inc/flat/ECatalog.hxx new file mode 100644 index 000000000..b28d110a3 --- /dev/null +++ b/connectivity/source/inc/flat/ECatalog.hxx @@ -0,0 +1,42 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ECATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ECATALOG_HXX + +#include <file/FCatalog.hxx> + +namespace connectivity +{ + namespace flat + { + class OFlatConnection; + class OFlatCatalog : public file::OFileCatalog + { + public: + virtual void refreshTables() override; + + public: + OFlatCatalog(OFlatConnection* _pCon); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ECATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/EColumns.hxx b/connectivity/source/inc/flat/EColumns.hxx new file mode 100644 index 000000000..800ac771f --- /dev/null +++ b/connectivity/source/inc/flat/EColumns.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ECOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ECOLUMNS_HXX + +#include <file/FColumns.hxx> + +namespace connectivity +{ + namespace flat + { + class OFlatColumns : public file::OColumns + { + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + public: + OFlatColumns(file::OFileTable* _pTable, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector + ) : file::OColumns(_pTable,_rMutex,_rVector) + {} + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ECOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/EConnection.hxx b/connectivity/source/inc/flat/EConnection.hxx new file mode 100644 index 000000000..36f6d0f49 --- /dev/null +++ b/connectivity/source/inc/flat/EConnection.hxx @@ -0,0 +1,66 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ECONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ECONNECTION_HXX + +#include <file/FConnection.hxx> + +namespace connectivity +{ + namespace flat + { + class ODriver; + class OFlatConnection : public file::OConnection + { + private: + sal_Int32 m_nMaxRowsToScan; + bool m_bHeaderLine; // column names in first row + sal_Unicode m_cFieldDelimiter; // look at the name + sal_Unicode m_cStringDelimiter; + sal_Unicode m_cDecimalDelimiter; + sal_Unicode m_cThousandDelimiter; + public: + OFlatConnection(ODriver* _pDriver); + virtual ~OFlatConnection() override; + + virtual void construct(const OUString& _rUrl,const css::uno::Sequence< css::beans::PropertyValue >& _rInfo ) override; + + // own methods + bool isHeaderLine() const { return m_bHeaderLine; } + sal_Unicode getFieldDelimiter() const { return m_cFieldDelimiter; } + sal_Unicode getStringDelimiter() const { return m_cStringDelimiter; } + sal_Unicode getDecimalDelimiter() const { return m_cDecimalDelimiter; } + sal_Unicode getThousandDelimiter() const { return m_cThousandDelimiter;} + sal_Int32 getMaxRowsToScan() const { return m_nMaxRowsToScan;} + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // XConnection + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > createCatalog() override; + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + }; + } +} +#endif // _CONNECTIVITY_FLAT_DCONNECTION_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/EDatabaseMetaData.hxx b/connectivity/source/inc/flat/EDatabaseMetaData.hxx new file mode 100644 index 000000000..f5c1bdd3c --- /dev/null +++ b/connectivity/source/inc/flat/EDatabaseMetaData.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_EDATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_EDATABASEMETADATA_HXX + +#include <file/FDatabaseMetaData.hxx> + +namespace connectivity +{ + namespace flat + { + + //************ Class: java.sql.DatabaseMetaDataDate + + + class OFlatDatabaseMetaData : public file::ODatabaseMetaData + { + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + protected: + virtual ~OFlatDatabaseMetaData() override; + public: + OFlatDatabaseMetaData(file::OConnection* _pCon); + + virtual OUString SAL_CALL getURL( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + }; + } +} +#endif // _CONNECTIVITY_FLAT_ODATABASEMETADATA_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/EDriver.hxx b/connectivity/source/inc/flat/EDriver.hxx new file mode 100644 index 000000000..c818b3632 --- /dev/null +++ b/connectivity/source/inc/flat/EDriver.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_EDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_EDRIVER_HXX + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <connectivity/CommonTools.hxx> +#include <file/FDriver.hxx> + +namespace connectivity +{ + namespace flat + { + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > ODriver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + class ODriver : public file::OFileDriver + { + public: + ODriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext) : file::OFileDriver(_rxContext){} + + // XInterface + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + // static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ) throw (css::uno::RuntimeException); + + OUString SAL_CALL getImplementationName( ) override; + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + }; + } + +} +#endif //_CONNECTIVITY_FLAT_DDRIVER_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/EPreparedStatement.hxx b/connectivity/source/inc/flat/EPreparedStatement.hxx new file mode 100644 index 000000000..3af19bd94 --- /dev/null +++ b/connectivity/source/inc/flat/EPreparedStatement.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_EPREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_EPREPAREDSTATEMENT_HXX + +#include <file/FPreparedStatement.hxx> + +namespace connectivity +{ + namespace flat + { + class OConnection; + class OFlatPreparedStatement : public file::OPreparedStatement + { + protected: + virtual file::OResultSet* createResultSet() override; + public: + OFlatPreparedStatement( file::OConnection* _pConnection) : file::OPreparedStatement( _pConnection){} + DECLARE_SERVICE_INFO(); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_EPREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/EResultSet.hxx b/connectivity/source/inc/flat/EResultSet.hxx new file mode 100644 index 000000000..e7b7c6d87 --- /dev/null +++ b/connectivity/source/inc/flat/EResultSet.hxx @@ -0,0 +1,74 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ERESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ERESULTSET_HXX + +#include <file/FResultSet.hxx> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <cppuhelper/implbase1.hxx> + +namespace connectivity +{ + namespace flat + { + class OFlatResultSet; + // these typedef's are only necessary for the compiler + typedef ::cppu::ImplHelper1< css::sdbcx::XRowLocate> OFlatResultSet_BASE; + typedef file::OResultSet OFlatResultSet_BASE2; + typedef ::comphelper::OPropertyArrayUsageHelper<OFlatResultSet> OFlatResultSet_BASE3; + + + class OFlatResultSet : public OFlatResultSet_BASE2, + public OFlatResultSet_BASE, + public OFlatResultSet_BASE3 + { + bool m_bBookmarkable; + protected: + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + public: + DECLARE_SERVICE_INFO(); + + OFlatResultSet( file::OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // XRowLocate + virtual css::uno::Any SAL_CALL getBookmark( ) override; + virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override; + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override; + virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override; + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override; + virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override; + }; + } +} +#endif //_CONNECTIVITY_FLAT_DRESULTSET_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/EStatement.hxx b/connectivity/source/inc/flat/EStatement.hxx new file mode 100644 index 000000000..215d0b0a9 --- /dev/null +++ b/connectivity/source/inc/flat/EStatement.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ESTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ESTATEMENT_HXX + +#include <file/FStatement.hxx> + +namespace connectivity +{ + namespace flat + { + class OConnection; + class OFlatStatement : public file::OStatement + { + protected: + virtual file::OResultSet* createResultSet() override; + public: + OFlatStatement( file::OConnection* _pConnection) : file::OStatement( _pConnection){} + DECLARE_SERVICE_INFO(); + }; + } +} + +#endif //_CONNECTIVITY_FLAT_DSTATEMENT_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/ETable.hxx b/connectivity/source/inc/flat/ETable.hxx new file mode 100644 index 000000000..6680c2585 --- /dev/null +++ b/connectivity/source/inc/flat/ETable.hxx @@ -0,0 +1,108 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ETABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ETABLE_HXX + +#include <file/FTable.hxx> +#include <flat/EConnection.hxx> +#include <connectivity/CommonTools.hxx> +#include <file/quotedstring.hxx> +#include <unotools/syslocale.hxx> +#include <com/sun/star/util/XNumberFormatter.hpp> + +namespace connectivity +{ + namespace flat + { + typedef file::OFileTable OFlatTable_BASE; + class OFlatConnection; + + typedef std::pair<sal_Int32, sal_Int32> TRowPositionInFile; + + class OFlatTable : public OFlatTable_BASE + { + // maps a row position to a file position + // row n is positions [m_aRowPosToFilePos[n]->first, m_aRowPosToFilePos[n]->second) in file + // "real" row indexes start at 1; for the purposes of m_aRowPosToFilePos, row 0 is headers + std::vector<TRowPositionInFile> + m_aRowPosToFilePos; + std::vector<sal_Int32> m_aTypes; // holds all type for columns just to avoid to ask the propertyset + std::vector<sal_Int32> m_aPrecisions; // same as aboth + std::vector<sal_Int32> m_aScales; + QuotedTokenizedString m_aCurrentLine; + css::uno::Reference< css::util::XNumberFormatter > m_xNumberFormatter; + css::util::Date m_aNullDate; + sal_Int32 m_nRowPos; + sal_Int32 m_nMaxRowCount; // will be set if stream is once eof + sal_Unicode m_cStringDelimiter; // delimiter for strings m_cStringDelimiter blabla m_cStringDelimiter + sal_Unicode m_cFieldDelimiter; // look at the name + bool m_bNeedToReadLine; + private: + void fillColumns(const css::lang::Locale& _aLocale); + bool readLine(sal_Int32 *pEndPos, sal_Int32 *pStartPos, bool nonEmpty = false); + void setRowPos(std::vector<TRowPositionInFile>::size_type rowNum, const TRowPositionInFile &rowPos); + void impl_fillColumnInfo_nothrow(QuotedTokenizedString const & aFirstLine, sal_Int32& nStartPosFirstLine, sal_Int32& nStartPosFirstLine2, + sal_Int32& io_nType, sal_Int32& io_nPrecisions, sal_Int32& io_nScales, OUString& o_sTypeName, + const sal_Unicode cDecimalDelimiter, const sal_Unicode cThousandDelimiter, const CharClass& aCharClass); + OFlatConnection* getFlatConnection() + { +#if OSL_DEBUG_LEVEL > 0 + OFlatConnection* pConnection = dynamic_cast<OFlatConnection*>(m_pConnection); + assert(pConnection); +#else + OFlatConnection* pConnection = static_cast<OFlatConnection*>(m_pConnection); +#endif + return pConnection; + } + public: + virtual void refreshColumns() override; + + public: + // DECLARE_CTY_DEFAULTS( OFlatTable_BASE); + OFlatTable( sdbcx::OCollection* _pTables,OFlatConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description = OUString(), + const OUString& SchemaName = OUString(), + const OUString& CatalogName = OUString() + ); + + void construct() override; // can throw any exception + + virtual bool seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) override; + virtual bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override; + virtual void refreshHeader() override; + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual void SAL_CALL disposing() override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + OUString getEntry() const; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ETABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/flat/ETables.hxx b/connectivity/source/inc/flat/ETables.hxx new file mode 100644 index 000000000..69b6f5562 --- /dev/null +++ b/connectivity/source/inc/flat/ETables.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ETABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ETABLES_HXX + +#include <file/FTables.hxx> + +namespace connectivity +{ + namespace flat + { + typedef file::OTables OFlatTables_BASE; + + class OFlatTables : public OFlatTables_BASE + { + protected: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + public: + OFlatTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : OFlatTables_BASE(_rMetaData,_rParent,_rMutex,_rVector) + {} + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_FLAT_ETABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HCatalog.hxx b/connectivity/source/inc/hsqldb/HCatalog.hxx new file mode 100644 index 000000000..0202da350 --- /dev/null +++ b/connectivity/source/inc/hsqldb/HCatalog.hxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCATALOG_HXX + +#include <sdbcx/VCatalog.hxx> + +namespace connectivity +{ + namespace hsqldb + { + // please don't name the class the same name as in another namespaces + // some compilers have problems with this task as I noticed on windows + class OHCatalog : public connectivity::sdbcx::OCatalog + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + + /** calls XDatabaseMetaData::getTables. + @param _sKindOfObject + The type of tables to be fetched. + @param _rNames + The container for the names to be filled. + */ + void refreshObjects(const css::uno::Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames); + + public: + // implementation of the pure virtual methods + virtual void refreshTables() override; + virtual void refreshViews() override ; + virtual void refreshGroups() override; + virtual void refreshUsers() override ; + + public: + OHCatalog(const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + + sdbcx::OCollection* getPrivateTables() const { return m_pTables.get(); } + sdbcx::OCollection* getPrivateViews() const { return m_pViews.get(); } + const css::uno::Reference< css::sdbc::XConnection >& getConnection() const { return m_xConnection; } + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + // ::cppu::OComponentHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HColumns.hxx b/connectivity/source/inc/hsqldb/HColumns.hxx new file mode 100644 index 000000000..f3fd008cd --- /dev/null +++ b/connectivity/source/inc/hsqldb/HColumns.hxx @@ -0,0 +1,60 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCOLUMNS_HXX +#include <connectivity/TColumnsHelper.hxx> +#include <connectivity/sdbcx/VColumn.hxx> + +namespace connectivity +{ + namespace hsqldb + { + class OHSQLColumns : public OColumnsHelper + { + protected: + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + public: + OHSQLColumns( ::cppu::OWeakObject& _rParent + ,::osl::Mutex& _rMutex + ,const ::std::vector< OUString> &_rVector + ); + }; + + class OHSQLColumn; + typedef ::comphelper::OIdPropertyArrayUsageHelper<OHSQLColumn> OHSQLColumn_PROP; + + class OHSQLColumn : public sdbcx::OColumn, + public OHSQLColumn_PROP + { + OUString m_sAutoIncrement; + protected: + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + public: + OHSQLColumn(); + virtual void construct() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HConnection.hxx b/connectivity/source/inc/hsqldb/HConnection.hxx new file mode 100644 index 000000000..dcc2eb49f --- /dev/null +++ b/connectivity/source/inc/hsqldb/HConnection.hxx @@ -0,0 +1,149 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCONNECTION_HXX + +#include <connectivity/ConnectionWrapper.hxx> +#include <com/sun/star/util/XFlushable.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdb/application/XTableUIProvider.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <comphelper/uno3.hxx> +#include <comphelper/interfacecontainer2.hxx> + +namespace connectivity +{ + namespace hsqldb + { + class SAL_NO_VTABLE IMethodGuardAccess + { + public: + virtual ::osl::Mutex& getMutex() const = 0; + virtual void checkDisposed() const = 0; + + protected: + ~IMethodGuardAccess() {} + }; + + + // OHsqlConnection - wraps all methods to the real connection from the driver + // but when disposed it doesn't dispose the real connection + + typedef ::cppu::WeakComponentImplHelper< css::util::XFlushable + , css::sdb::application::XTableUIProvider + > OHsqlConnection_BASE; + + class OHsqlConnection :public cppu::BaseMutex + ,public OHsqlConnection_BASE + ,public OConnectionWrapper + ,public IMethodGuardAccess + { + private: + ::comphelper::OInterfaceContainerHelper2 m_aFlushListeners; + css::uno::Reference< css::sdbc::XDriver > m_xDriver; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + bool m_bIni; + bool m_bReadOnly; + + protected: + virtual void SAL_CALL disposing() override; + virtual ~OHsqlConnection() override; + + public: + OHsqlConnection( + const css::uno::Reference< css::sdbc::XDriver >& _rxDriver, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const css::uno::Reference< css::uno::XComponentContext>& _rxContext + ); + + // XServiceInfo + DECLARE_SERVICE_INFO(); + DECLARE_XTYPEPROVIDER() + DECLARE_XINTERFACE( ) + + // IMethodGuardAccess + virtual ::osl::Mutex& getMutex() const override; + virtual void checkDisposed() const override; + + // XFlushable + virtual void SAL_CALL flush( ) override; + virtual void SAL_CALL addFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override; + virtual void SAL_CALL removeFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override; + + // XTableUIProvider + virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL getTableIcon( const OUString& TableName, ::sal_Int32 ColorMode ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getTableEditor( const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& DocumentUI, const OUString& TableName ) override; + + private: + + /** retrieves our table container + @return + our table container. Guaranteed to not be <NULL/>. + @throws css::lang::WrappedTargetException + if a non-RuntimeException is caught during obtaining the container. + @throws css::uno::RuntimeException + if a serious error occurs + @precond + We're not disposed. + */ + css::uno::Reference< css::container::XNameAccess > + impl_getTableContainer_throw(); + + /** checks whether the given table name denotes an existing table + @param _rTableName + the fully name of the table to check for existence + @throws css::lang::IllegalArgumentException + if the name does not denote an existing table + @precond + We're not disposed. + */ + void impl_checkExistingTable_throw( const OUString& _rTableName ); + + /** checks whether the given table name refers to a HSQL TEXT TABLE + */ + bool impl_isTextTable_nothrow( const OUString& _rTableName ); + + /** retrieves the icon for HSQL TEXT TABLEs + */ + css::uno::Reference< css::graphic::XGraphic > + impl_getTextTableIcon_nothrow(); + }; + + + // OHsqlConnection + + class MethodGuard : public ::osl::MutexGuard + { + private: + typedef ::osl::MutexGuard BaseGuard; + + public: + MethodGuard( const IMethodGuardAccess& _rComponent ) + :BaseGuard( _rComponent.getMutex() ) + { + _rComponent.checkDisposed(); + } + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HDriver.hxx b/connectivity/source/inc/hsqldb/HDriver.hxx new file mode 100644 index 000000000..4df9a546d --- /dev/null +++ b/connectivity/source/inc/hsqldb/HDriver.hxx @@ -0,0 +1,139 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HDRIVER_HXX + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <com/sun/star/sdbcx/XCreateCatalog.hpp> +#include <com/sun/star/embed/XTransactionListener.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <connectivity/CommonTools.hxx> + + +namespace connectivity +{ + + + namespace hsqldb + { + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > ODriverDelegator_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver + , css::sdbcx::XDataDefinitionSupplier + , css::lang::XServiceInfo + , css::sdbcx::XCreateCatalog + , css::embed::XTransactionListener + > ODriverDelegator_BASE; + + typedef std::pair< css::uno::WeakReferenceHelper,css::uno::WeakReferenceHelper> TWeakRefPair; + typedef std::pair< OUString ,TWeakRefPair > TWeakConnectionPair; + + typedef std::pair< css::uno::WeakReferenceHelper,TWeakConnectionPair> TWeakPair; + typedef std::vector< TWeakPair > TWeakPairVector; + + + /** delegates all calls to the original driver and extend the existing one with the SDBCX layer. + + */ + class ODriverDelegator final : public ::cppu::BaseMutex + ,public ODriverDelegator_BASE + { + TWeakPairVector m_aConnections; // vector containing a list + // of all the Connection objects + // for this Driver + css::uno::Reference< css::sdbc::XDriver > m_xDriver; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + bool m_bInShutDownConnections; + + /** load the driver we want to delegate. + The <member>m_xDriver</member> may be <NULL/> if the driver could not be loaded. + @return + The driver which was currently selected. + */ + css::uno::Reference< css::sdbc::XDriver > const & loadDriver( ); + + /** shut down the connection and revoke the storage from the map + @param _aIter + The connection to shut down and storage to revoke. + */ + void shutdownConnection(const TWeakPairVector::iterator& _aIter); + + public: + /** creates a new delegator for a HSQLDB driver + */ + ODriverDelegator(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + // XServiceInfo + DECLARE_SERVICE_INFO(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + + // XDataDefinitionSupplier + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + // XCreateCatalog + virtual void SAL_CALL createCatalog( const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // XTransactionListener + virtual void SAL_CALL preCommit( const css::lang::EventObject& aEvent ) override; + virtual void SAL_CALL commited( const css::lang::EventObject& aEvent ) override; + virtual void SAL_CALL preRevert( const css::lang::EventObject& aEvent ) override; + virtual void SAL_CALL reverted( const css::lang::EventObject& aEvent ) override; + + void shutdownConnections(); + void flushConnections(); + private: + /// dtor + virtual ~ODriverDelegator() override; + // OComponentHelper + virtual void SAL_CALL disposing() override; + + /** called when we connected to a newly created embedded database + */ + void onConnectedNewDatabase( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection + ); + }; + } + + +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HDRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HStorageAccess.hxx b/connectivity/source/inc/hsqldb/HStorageAccess.hxx new file mode 100644 index 000000000..457d1eaff --- /dev/null +++ b/connectivity/source/inc/hsqldb/HStorageAccess.hxx @@ -0,0 +1,39 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HSTORAGEACCESS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HSTORAGEACCESS_HXX + +#include <sal/config.h> + +#include <jni.h> + +namespace connectivity::hsqldb +{ + class DataLogFile; +} + +jint read_from_storage_stream( JNIEnv * env, jstring name, jstring key ); +jint read_from_storage_stream_into_buffer( JNIEnv * env, jstring name, jstring key, jbyteArray buffer, jint off, jint len ); +void write_to_storage_stream_from_buffer( JNIEnv* env, jstring name, jstring key, jbyteArray buffer, jint off, jint len ); +void write_to_storage_stream( JNIEnv* env, jstring name, jstring key, jint v ); + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HSTORAGEACCESS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HStorageMap.hxx b/connectivity/source/inc/hsqldb/HStorageMap.hxx new file mode 100644 index 000000000..62ae7ec3d --- /dev/null +++ b/connectivity/source/inc/hsqldb/HStorageMap.hxx @@ -0,0 +1,97 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HSTORAGEMAP_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HSTORAGEMAP_HXX + +#include <sal/config.h> + +#include <map> +#include <memory> + +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XTransactionListener.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <jni.h> +#include <uno/environment.hxx> + +namespace connectivity +{ + + namespace hsqldb + { + class StreamHelper + { + css::uno::Reference< css::io::XStream> m_xStream; + css::uno::Reference< css::io::XSeekable> m_xSeek; + css::uno::Reference< css::io::XOutputStream> m_xOutputStream; + css::uno::Reference< css::io::XInputStream> m_xInputStream; + public: + StreamHelper(const css::uno::Reference< css::io::XStream>& _xStream); + ~StreamHelper(); + + css::uno::Reference< css::io::XInputStream> const & getInputStream(); + css::uno::Reference< css::io::XOutputStream> const & getOutputStream(); + css::uno::Reference< css::io::XSeekable> const & getSeek(); + }; + + + typedef std::map< OUString, std::shared_ptr<StreamHelper> > TStreamMap; + + struct StorageData { + css::uno::Reference<css::embed::XStorage> storage; + css::uno::Environment storageEnvironment; + OUString url; + TStreamMap streams; + + css::uno::Reference<css::embed::XStorage> mapStorage() const; + }; + + typedef std::map<OUString, StorageData> TStorages; + /** contains all storages so far accessed. + */ + class StorageContainer + { + public: + static OUString registerStorage(const css::uno::Reference< css::embed::XStorage>& _xStorage,const OUString& _sURL); + static TStorages::mapped_type getRegisteredStorage(const OUString& _sKey); + static OUString getRegisteredKey(const css::uno::Reference< css::embed::XStorage>& _xStorage); + static void revokeStorage(const OUString& _sKey,const css::uno::Reference< css::embed::XTransactionListener>& _xListener); + + static TStreamMap::mapped_type registerStream(JNIEnv * env,jstring name, jstring key,sal_Int32 _nMode); + static void revokeStream(JNIEnv * env,jstring name, jstring key); + static TStreamMap::mapped_type getRegisteredStream( JNIEnv * env, jstring name, jstring key); + + static OUString jstring2ustring(JNIEnv * env, jstring jstr); + static OUString removeURLPrefix(const OUString& _sURL,const OUString& _sFileURL); + static OUString removeOldURLPrefix(const OUString& _sURL); + static void throwJavaException(const css::uno::Exception& _aException,JNIEnv * env); + }; + + } // namespace hsqldb + + +} // namespace connectivity + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HSTORAGEMAP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HTable.hxx b/connectivity/source/inc/hsqldb/HTable.hxx new file mode 100644 index 000000000..4540bb089 --- /dev/null +++ b/connectivity/source/inc/hsqldb/HTable.hxx @@ -0,0 +1,115 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTABLE_HXX + +#include <connectivity/TTableHelper.hxx> +#include <comphelper/IdPropArrayHelper.hxx> + +namespace connectivity +{ + namespace hsqldb + { + + class OHSQLTable; + typedef ::comphelper::OIdPropertyArrayUsageHelper< OHSQLTable > OHSQLTable_PROP; + class OHSQLTable : public OTableHelper + ,public OHSQLTable_PROP + { + sal_Int32 m_nPrivileges; // we have to set our privileges by our own + + /** executes the statement. + @param _rStatement + The statement to execute. + */ + void executeStatement(const OUString& _rStatement ); + protected: + + /** creates the column collection for the table + @param _rNames + The column names. + */ + virtual sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override; + + /** creates the key collection for the table + @param _rNames + The key names. + */ + virtual sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override; + + /** creates the index collection for the table + @param _rNames + The index names. + */ + virtual sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override; + + /** used to implement the creation of the array helper which is shared amongst all instances of the class. + This method needs to be implemented in derived classes. + <BR> + The method gets called with s_aMutex acquired. + @return a pointer to the newly created array helper. Must not be NULL. + */ + virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + public: + OHSQLTable( sdbcx::OCollection* _pTables, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + OHSQLTable( sdbcx::OCollection* _pTables, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description, + const OUString& SchemaName, + const OUString& CatalogName, + sal_Int32 _nPrivileges + ); + + // ODescriptor + virtual void construct() override; + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XAlterTable + virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + + // XRename + virtual void SAL_CALL rename( const OUString& newName ) override; + + /** + returns the ALTER TABLE XXX COLUMN statement + */ + OUString getAlterTableColumnPart() const; + + // some methods to alter table structures + void alterColumnType(sal_Int32 nNewType,const OUString& _rColName,const css::uno::Reference< css::beans::XPropertySet >& _xDescriptor); + void alterDefaultValue(const OUString& _sNewDefault,const OUString& _rColName); + void dropDefaultValue(const OUString& _sNewDefault); + + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HTables.hxx b/connectivity/source/inc/hsqldb/HTables.hxx new file mode 100644 index 000000000..bf0580396 --- /dev/null +++ b/connectivity/source/inc/hsqldb/HTables.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTABLES_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +namespace connectivity +{ + namespace hsqldb + { + class OTables final : public sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + + void createTable( const css::uno::Reference< css::beans::XPropertySet >& descriptor ); + virtual OUString getNameForObject(const sdbcx::ObjectType& _xObject) override; + public: + OTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + ,m_xMetaData(_rMetaData) + {} + + // only the name is identical to ::cppu::OComponentHelper + virtual void disposing() override; + + // XDrop + void appendNew(const OUString& _rsNewTable); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HTools.hxx b/connectivity/source/inc/hsqldb/HTools.hxx new file mode 100644 index 000000000..be30e8e28 --- /dev/null +++ b/connectivity/source/inc/hsqldb/HTools.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTOOLS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTOOLS_HXX + +#include <rtl/ustrbuf.hxx> + + +namespace connectivity::hsqldb +{ + + class HTools + { + public: + /** appends a proper WHERE clause to the given buffer, which filters + for a given table name + + @param _bShortForm + <TRUE/> if the column names of the system table which is being asked + have the short form (TABLE_CAT instead of TABLE_CATALOG, and so on) + */ + static void appendTableFilterCrit( + OUStringBuffer& _inout_rBuffer, const OUString& _rCatalog, + const OUString& _rSchema, const OUString& _rName, + bool _bShortForm + ); + }; + + +} // namespace connectivity::hsqldb + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HTOOLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HUser.hxx b/connectivity/source/inc/hsqldb/HUser.hxx new file mode 100644 index 000000000..1e16a7652 --- /dev/null +++ b/connectivity/source/inc/hsqldb/HUser.hxx @@ -0,0 +1,77 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HUSER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HUSER_HXX + +#include <sdbcx/VUser.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> + +namespace connectivity +{ + namespace hsqldb + { + typedef connectivity::sdbcx::OUser OUser_TYPEDEF; + + class OHSQLUser : public OUser_TYPEDEF + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + + static OUString getPrivilegeString(sal_Int32 nRights); + // return the privileges and additional the grant rights + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant); + public: + virtual void refreshGroups() override; + public: + OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + OHSQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const OUString& Name); + + // XUser + virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override; + // XAuthorizable + virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + }; + + class OUserExtend; + typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP; + + class OUserExtend : public OHSQLUser, + public OUserExtend_PROP + { + OUString m_Password; + protected: + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + public: + OUserExtend(const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + + virtual void construct() override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HUSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HUsers.hxx b/connectivity/source/inc/hsqldb/HUsers.hxx new file mode 100644 index 000000000..392b3412a --- /dev/null +++ b/connectivity/source/inc/hsqldb/HUsers.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HUSERS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HUSERS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +namespace connectivity +{ + namespace sdbcx + { + class IRefreshableUsers; + } + namespace hsqldb + { + class OUsers : public sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + connectivity::sdbcx::IRefreshableUsers* m_pParent; + public: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual void impl_refresh() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + public: + OUsers( ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + connectivity::sdbcx::IRefreshableUsers* _pParent); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HUSERS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HView.hxx b/connectivity/source/inc/hsqldb/HView.hxx new file mode 100644 index 000000000..3e158c753 --- /dev/null +++ b/connectivity/source/inc/hsqldb/HView.hxx @@ -0,0 +1,91 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HVIEW_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HVIEW_HXX + +#include <connectivity/sdbcx/VView.hxx> + +#include <com/sun/star/sdbcx/XAlterView.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> + +#include <comphelper/uno3.hxx> +#include <cppuhelper/implbase1.hxx> + + +namespace connectivity::hsqldb +{ + + typedef ::connectivity::sdbcx::OView HView_Base; + typedef ::cppu::ImplHelper1< css::sdbcx::XAlterView > HView_IBASE; + class HView :public HView_Base + ,public HView_IBASE + { + public: + HView( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + bool _bCaseSensitive, + const OUString& _rSchemaName, + const OUString& _rName + ); + + // UNO + DECLARE_XINTERFACE() + DECLARE_XTYPEPROVIDER() + + // XAlterView + virtual void SAL_CALL alterCommand( const OUString& NewCommand ) override; + + protected: + virtual ~HView() override; + + protected: + // OPropertyContainer + virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override; + + private: + /** retrieves the current command of the View */ + OUString impl_getCommand() const; + + /** retrieves the current command of the View + + @throws css::lang::WrappedTargetException + if an error occurs while retrieving the command from the database. + */ + OUString impl_getCommand_wrapSQLException() const; + /** retrieves the current command of the View + + @throws css::sdbc::SQLException + if an error occurs while retrieving the command from the database. + */ + OUString impl_getCommand_throwSQLException() const; + + private: + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + private: + using HView_Base::getFastPropertyValue; + }; + + +} // namespace connectivity::hsqldb + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/hsqldb/HViews.hxx b/connectivity/source/inc/hsqldb/HViews.hxx new file mode 100644 index 000000000..6f6724383 --- /dev/null +++ b/connectivity/source/inc/hsqldb/HViews.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HVIEWS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HVIEWS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +namespace connectivity +{ + namespace hsqldb + { + class HViews final : public sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + bool m_bInDrop; + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + + void createView( const css::uno::Reference< css::beans::XPropertySet >& descriptor ); + public: + HViews( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, const ::std::vector< OUString> &_rVector ); + + // only the name is identical to ::cppu::OComponentHelper + virtual void disposing() override; + + void dropByNameImpl(const OUString& elementName); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HVIEWS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/ContextClassLoader.hxx b/connectivity/source/inc/java/ContextClassLoader.hxx new file mode 100644 index 000000000..dea3fb58b --- /dev/null +++ b/connectivity/source/inc/java/ContextClassLoader.hxx @@ -0,0 +1,82 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_CONTEXTCLASSLOADER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_CONTEXTCLASSLOADER_HXX + +#include <java/GlobalRef.hxx> + +namespace comphelper +{ + class EventLogger; +} + + +namespace connectivity::jdbc +{ + class ContextClassLoaderScope + { + public: + /** creates the instance. If isActive returns <FALSE/> afterwards, then an exception + happened in the JVM, which should be raised as UNO exception by the caller + + @param environment + the current JNI environment + @param newClassLoader + the new class loader to set at the current thread + @param _rLoggerForErrors + the logger which should be passed to java_lang_object::ThrowLoggedSQLException in case + an error occurs + @param _rxErrorContext + the context which should be passed to java_lang_object::ThrowLoggedSQLException in case + an error occurs + + */ + ContextClassLoaderScope( + JNIEnv& environment, + const GlobalRef< jobject >& newClassLoader, + const ::comphelper::EventLogger& _rLoggerForErrors, + const css::uno::Reference< css::uno::XInterface >& _rxErrorContext + ); + + ~ContextClassLoaderScope(); + + bool isActive() const + { + return ( m_currentThread.is() ) + && ( m_setContextClassLoaderMethod != nullptr ); + } + + private: + ContextClassLoaderScope(ContextClassLoaderScope const &) = delete; + ContextClassLoaderScope& operator =(ContextClassLoaderScope const &) = delete; + + JNIEnv& m_environment; + LocalRef< jobject > m_currentThread; + LocalRef< jobject > m_oldContextClassLoader; + jmethodID m_setContextClassLoaderMethod; + }; + + +} // namespace connectivity::jdbc + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_CONTEXTCLASSLOADER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/GlobalRef.hxx b/connectivity/source/inc/java/GlobalRef.hxx new file mode 100644 index 000000000..80888cb48 --- /dev/null +++ b/connectivity/source/inc/java/GlobalRef.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_GLOBALREF_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_GLOBALREF_HXX + +#include <java/LocalRef.hxx> +#include <java/lang/Object.hxx> + + +namespace connectivity::jdbc +{ + /** helper class to hold a local ref to a JNI object + */ + template< typename T > + class GlobalRef + { + public: + GlobalRef() + :m_object( nullptr ) + { + } + + GlobalRef( const GlobalRef& _source ) + :m_object( nullptr ) + { + *this = _source; + } + + GlobalRef& operator=( const GlobalRef& _source ) + { + if ( &_source == this ) + return *this; + + SDBThreadAttach t; + set( t.env(), _source.get() ); + return *this; + } + + ~GlobalRef() COVERITY_NOEXCEPT_FALSE + { + reset(); + } + + void reset() + { + if ( m_object != nullptr ) + { + SDBThreadAttach t; + t.env().DeleteGlobalRef( m_object ); + m_object = nullptr; + } + } + + void set( JNIEnv& _environment, T _object ) + { + if ( m_object != nullptr ) + _environment.DeleteGlobalRef( m_object ); + m_object = _object; + if ( m_object ) + m_object = static_cast< T >( _environment.NewGlobalRef( m_object ) ); + } + + void set( LocalRef< T >& _object ) + { + set( _object.env(), _object.release() ); + } + + T get() const + { + return m_object; + } + + bool is() const + { + return m_object != nullptr; + } + + private: + T m_object; + }; + + +} // namespace connectivity::jdbc + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_GLOBALREF_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/LocalRef.hxx b/connectivity/source/inc/java/LocalRef.hxx new file mode 100644 index 000000000..5973405ac --- /dev/null +++ b/connectivity/source/inc/java/LocalRef.hxx @@ -0,0 +1,92 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LOCALREF_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LOCALREF_HXX + +#include <jni.h> + + +namespace connectivity::jdbc +{ + + /** helper class to hold a local ref to a JNI object + + Note that this class never actually calls NewLocalRef. It is assumed that all objects + passed are already acquired with a local ref (as it usually is the case if you obtain + the object from a JNI method). + */ + template< typename T > + class LocalRef final + { + public: + explicit LocalRef( JNIEnv& environment ) + :m_environment( environment ) + ,m_object( nullptr ) + { + } + + LocalRef( JNIEnv& environment, T object ) + :m_environment( environment ) + ,m_object( object ) + { + } + + ~LocalRef() + { + reset(); + } + + T release() + { + T t = m_object; + m_object = nullptr; + return t; + } + + void set( T object ) { reset(); m_object = object; } + + void reset() + { + if ( m_object != nullptr ) + { + m_environment.DeleteLocalRef( m_object ); + m_object = nullptr; + } + } + + JNIEnv& env() const { return m_environment; } + T get() const { return m_object; } + bool is() const { return m_object != nullptr; } + + private: + LocalRef(LocalRef const &) = delete; + LocalRef& operator =(LocalRef const &) = delete; + + JNIEnv& m_environment; + T m_object; + }; + + +} // namespace connectivity::jdbc + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LOCALREF_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/io/InputStream.hxx b/connectivity/source/inc/java/io/InputStream.hxx new file mode 100644 index 000000000..c05309e87 --- /dev/null +++ b/connectivity/source/inc/java/io/InputStream.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_IO_INPUTSTREAM_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_IO_INPUTSTREAM_HXX + +#include <java/lang/Object.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/io/XInputStream.hpp> + +namespace connectivity +{ + + + //************ Class: java.io.InputStream + + class java_io_InputStream : public java_lang_Object, + public ::cppu::WeakImplHelper< css::io::XInputStream> + { + protected: + // static Data for the Class + static jclass theClass; + virtual ~java_io_InputStream() override; + public: + virtual jclass getMyClass() const override; + // a Constructor, that is needed for when Returning the Object is needed: + java_io_InputStream( JNIEnv * pEnv, jobject myObj ); + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override; + virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override; + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override; + virtual sal_Int32 SAL_CALL available( ) override; + virtual void SAL_CALL closeInput( ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_IO_INPUTSTREAM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/io/Reader.hxx b/connectivity/source/inc/java/io/Reader.hxx new file mode 100644 index 000000000..7a2cf0524 --- /dev/null +++ b/connectivity/source/inc/java/io/Reader.hxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_IO_READER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_IO_READER_HXX + +#include <java/lang/Object.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/io/XInputStream.hpp> +#include <optional> + +namespace connectivity +{ + + //************ Class: java.io.InputStream + + class java_io_Reader final : public java_lang_Object, + public ::cppu::WeakImplHelper< css::io::XInputStream> + { + // static Data for the Class + static jclass theClass; + virtual ~java_io_Reader() override; + std::optional<char> m_buf; + public: + virtual jclass getMyClass() const override; + // a Constructor, that is needed for when Returning the Object is needed: + java_io_Reader( JNIEnv * pEnv, jobject myObj ); + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override; + virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override; + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override; + virtual sal_Int32 SAL_CALL available( ) override; + virtual void SAL_CALL closeInput( ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_IO_READER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/lang/Boolean.hxx b/connectivity/source/inc/java/lang/Boolean.hxx new file mode 100644 index 000000000..27a7e0668 --- /dev/null +++ b/connectivity/source/inc/java/lang/Boolean.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_BOOLEAN_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_BOOLEAN_HXX + +#include <java/lang/Object.hxx> + +//************ Class: java.lang.Boolean + +namespace connectivity +{ + class java_lang_Boolean : public java_lang_Object + { + protected: + // static Data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_lang_Boolean() override; + // a Constructor, that is needed for when Returning the Object is needed: + java_lang_Boolean( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){} + + static jclass st_getMyClass(); + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_BOOLEAN_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/lang/Class.hxx b/connectivity/source/inc/java/lang/Class.hxx new file mode 100644 index 000000000..bc68a01a5 --- /dev/null +++ b/connectivity/source/inc/java/lang/Class.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_CLASS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_CLASS_HXX + +//************ Class: java.lang.Class + +#include <java/lang/Object.hxx> + +namespace connectivity +{ + class java_lang_Class : public java_lang_Object + { + protected: + // static Data for the Class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_lang_Class() override; + // a Constructor, that is needed for when Returning the Object is needed: + java_lang_Class( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){} + + static java_lang_Class * forName( const OUString &_par0 ); + // return the jre object + jobject newInstanceObject(); + + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_CLASS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/lang/Exception.hxx b/connectivity/source/inc/java/lang/Exception.hxx new file mode 100644 index 000000000..5e11e7890 --- /dev/null +++ b/connectivity/source/inc/java/lang/Exception.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_EXCEPTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_EXCEPTION_HXX + +#include <java/lang/Throwable.hxx> + +namespace connectivity +{ + + + //************ Class: java.lang.Exception + + class java_lang_Exception : public java_lang_Throwable{ + protected: + // statis Data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_lang_Exception() override; + // a Constructor, that is needed for when Returning the Object is needed: + java_lang_Exception( JNIEnv * pEnv, jobject myObj ) : java_lang_Throwable( pEnv, myObj ){} + + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_EXCEPTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/lang/Object.hxx b/connectivity/source/inc/java/lang/Object.hxx new file mode 100644 index 000000000..ba9414008 --- /dev/null +++ b/connectivity/source/inc/java/lang/Object.hxx @@ -0,0 +1,149 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_OBJECT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_OBJECT_HXX + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <jvmaccess/virtualmachine.hxx> + +#ifdef HAVE_64BIT_POINTERS +#error "no 64 bit pointer" +#endif //HAVE_64BIT_POINTERS + +namespace comphelper +{ + class EventLogger; +} + +namespace connectivity +{ + class SDBThreadAttach + { + jvmaccess::VirtualMachine::AttachGuard m_aGuard; + SDBThreadAttach(SDBThreadAttach const &) = delete; + SDBThreadAttach& operator= (SDBThreadAttach const &) = delete; + public: + SDBThreadAttach(); + ~SDBThreadAttach(); + + JNIEnv* pEnv; + static void addRef(); + static void releaseRef(); + + public: + JNIEnv& env() const + { + // according to the documentation of jvmaccess::VirtualMachine::AttachGuard, our env is never + // NULL, so why bothering with pointer checks? + return *pEnv; + } + }; + + + class java_lang_Object + { + java_lang_Object& operator= (java_lang_Object const &) = delete; + java_lang_Object(java_lang_Object const &) = delete; + + protected: + // The Java handle to this class + jobject object; + + // Class definition + // New in SJ2: + static jclass theClass; // The class needs to be requested only once! + + virtual jclass getMyClass() const; + + public: + // Ctor that should be used for the derived classes + java_lang_Object( JNIEnv * pEnv, jobject myObj ); + + // The actual ctor + java_lang_Object(); + + virtual ~java_lang_Object() COVERITY_NOEXCEPT_FALSE; + + void saveRef( JNIEnv * pEnv, jobject myObj ); + jobject getJavaObject() const { return object; } + void clearObject(JNIEnv& rEnv); + void clearObject(); + + OUString toString() const; + + static void ThrowSQLException(JNIEnv * pEnv,const css::uno::Reference< css::uno::XInterface> & _rContext); + static void ThrowLoggedSQLException( + const ::comphelper::EventLogger& _rLogger, + JNIEnv* pEnvironment, + const css::uno::Reference< css::uno::XInterface >& _rxContext + ); + static void ThrowRuntimeException(JNIEnv * pEnv,const css::uno::Reference< css::uno::XInterface> & _rContext); + + static ::rtl::Reference< jvmaccess::VirtualMachine > getVM(const css::uno::Reference< css::uno::XComponentContext >& _rxContext=nullptr); + + static jclass findMyClass(const char* _pClassName); + void obtainMethodId_throwSQL(JNIEnv* _pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID) const; + void obtainMethodId_throwRuntime(JNIEnv* _pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID) const; + + bool callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const; + bool callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const; + jobject callResultSetMethod( JNIEnv& _rEnv, const char* _pMethodName, jmethodID& _inout_MethodID ) const; + sal_Int32 callIntMethod_ThrowSQL(const char* _pMethodName, jmethodID& _inout_MethodID) const; + sal_Int32 callIntMethod_ThrowRuntime(const char* _pMethodName, jmethodID& _inout_MethodID) const; + sal_Int32 callIntMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const; + sal_Int32 callIntMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const; + sal_Int32 callIntMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID,const OUString& _nArgument ) const; + OUString callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ) const; + OUString callStringMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const; + void callVoidMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID) const; + void callVoidMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID) const; + void callVoidMethodWithIntArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const; + void callVoidMethodWithIntArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ) const; + void callVoidMethodWithBoolArg_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const; + void callVoidMethodWithBoolArg_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID, bool _nArgument ) const; + void callVoidMethodWithStringArg( const char* _pMethodName, jmethodID& _inout_MethodID, const OUString& _nArgument ) const; + jobject callObjectMethod( JNIEnv * pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID ) const; + jobject callObjectMethodWithIntArg( JNIEnv * pEnv, const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const; + + template< typename T > + T callMethodWithIntArg(T (JNIEnv::*pCallMethod)( jobject obj, jmethodID methodID, ... ) ,const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID , sal_Int32 _nArgument) const + { + SDBThreadAttach t; + obtainMethodId_throwSQL(t.pEnv, _pMethodName,_pSignature, _inout_MethodID); + T out = (t.pEnv->*pCallMethod)( object, _inout_MethodID,_nArgument); + ThrowSQLException( t.pEnv, nullptr ); + return out; + } + + template< typename T > + void callVoidMethod_ThrowSQL(const char* _pMethodName, const char* _pSignature, jmethodID& _inout_MethodID,sal_Int32 _nArgument, const T& _aValue) const + { + SDBThreadAttach t; + obtainMethodId_throwSQL(t.pEnv, _pMethodName,_pSignature, _inout_MethodID); + t.pEnv->CallVoidMethod( object, _inout_MethodID,_nArgument,_aValue); + ThrowSQLException( t.pEnv, nullptr ); + } + + + }; +} +#endif //_CONNECTIVITY_JAVA_LANG_OBJECT_HXX_ + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/lang/String.hxx b/connectivity/source/inc/java/lang/String.hxx new file mode 100644 index 000000000..25ba03d0d --- /dev/null +++ b/connectivity/source/inc/java/lang/String.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_STRING_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_STRING_HXX + +#include <java/lang/Object.hxx> + +namespace connectivity +{ + class java_lang_String : public java_lang_Object + { + protected: + // statis Data for the Class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_lang_String() override; + // a Constructor, that is needed for when Returning the Object is needed: + java_lang_String( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){} + + operator OUString(); + + static jclass st_getMyClass(); + }; + +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_STRING_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/lang/Throwable.hxx b/connectivity/source/inc/java/lang/Throwable.hxx new file mode 100644 index 000000000..d24395286 --- /dev/null +++ b/connectivity/source/inc/java/lang/Throwable.hxx @@ -0,0 +1,51 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_THROWABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_THROWABLE_HXX + +#include <java/lang/Object.hxx> + +namespace connectivity +{ + + //************ Class: java.lang.Throwable + + class java_lang_Throwable : public java_lang_Object + { + protected: + // static Data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_lang_Throwable() override; + // a Constructor, that is needed for when Returning the Object is needed: + java_lang_Throwable( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){} + OUString getMessage() const; + OUString getLocalizedMessage() const; + +#if OSL_DEBUG_LEVEL > 0 + void printStackTrace() const; +#endif + + static jclass st_getMyClass(); + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_LANG_THROWABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/math/BigDecimal.hxx b/connectivity/source/inc/java/math/BigDecimal.hxx new file mode 100644 index 000000000..e345aeed2 --- /dev/null +++ b/connectivity/source/inc/java/math/BigDecimal.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_MATH_BIGDECIMAL_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_MATH_BIGDECIMAL_HXX + +#include <java/lang/Object.hxx> + +//************ Class: java.lang.Boolean + +namespace connectivity +{ + class java_math_BigDecimal : public java_lang_Object + { + // static Data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_math_BigDecimal() override; + + java_math_BigDecimal( const OUString& _par0 ); + java_math_BigDecimal( const double& _par0 ); + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_MATH_BIGDECIMAL_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/Array.hxx b/connectivity/source/inc/java/sql/Array.hxx new file mode 100644 index 000000000..8677daa47 --- /dev/null +++ b/connectivity/source/inc/java/sql/Array.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_ARRAY_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_ARRAY_HXX + +#include <java/lang/Object.hxx> +#include <com/sun/star/sdbc/XArray.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity +{ + + + //************ Class: java.sql.SQLWarning + + class java_sql_Array : public java_lang_Object, + public ::cppu::WeakImplHelper< css::sdbc::XArray> + { + protected: + // Static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_sql_Array() override; + // A ctor that is needed for returning the object + java_sql_Array( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){} + + // XArray + virtual OUString SAL_CALL getBaseTypeName( ) override; + virtual sal_Int32 SAL_CALL getBaseType( ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArray( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getArrayAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSetAtIndex( sal_Int32 index, sal_Int32 count, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_ARRAY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/Blob.hxx b/connectivity/source/inc/java/sql/Blob.hxx new file mode 100644 index 000000000..605853f60 --- /dev/null +++ b/connectivity/source/inc/java/sql/Blob.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_BLOB_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_BLOB_HXX + +#include <java/lang/Object.hxx> +#include <com/sun/star/sdbc/XBlob.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity +{ + + + //************ Class: java.sql.SQLWarning + + class java_sql_Blob : public java_lang_Object, + public ::cppu::WeakImplHelper< css::sdbc::XBlob> + { + protected: + // Static data for the class + static jclass theClass; + virtual ~java_sql_Blob() override; + public: + virtual jclass getMyClass() const override; + + // A ctor that is needed for returning the object + java_sql_Blob( JNIEnv * pEnv, jobject myObj ); + + // XBlob + virtual sal_Int64 SAL_CALL length( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int64 pos, sal_Int32 length ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( ) override; + virtual sal_Int64 SAL_CALL position( const css::uno::Sequence< sal_Int8 >& pattern, sal_Int64 start ) override; + virtual sal_Int64 SAL_CALL positionOfBlob( const css::uno::Reference< css::sdbc::XBlob >& pattern, sal_Int64 start ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_BLOB_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/CallableStatement.hxx b/connectivity/source/inc/java/sql/CallableStatement.hxx new file mode 100644 index 000000000..31cafdeed --- /dev/null +++ b/connectivity/source/inc/java/sql/CallableStatement.hxx @@ -0,0 +1,84 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CALLABLESTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CALLABLESTATEMENT_HXX + +#include <java/sql/PreparedStatement.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XOutParameters.hpp> + +namespace connectivity +{ + + + //************ Class: java.sql.CallableStatement + + + class java_sql_CallableStatement : public java_sql_PreparedStatement, + public css::sdbc::XRow, + public css::sdbc::XOutParameters + { + protected: + // Static data for the class + static jclass theClass; + virtual void createStatement(JNIEnv* _pEnv) override; + + virtual ~java_sql_CallableStatement() override; + public: + DECLARE_SERVICE_INFO(); + virtual jclass getMyClass() const override; + + // A ctor that is needed for returning the object + java_sql_CallableStatement( JNIEnv * pEnv, java_sql_Connection& _rCon, const OUString& sql ); + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XOutParameters + virtual void SAL_CALL registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CALLABLESTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/Clob.hxx b/connectivity/source/inc/java/sql/Clob.hxx new file mode 100644 index 000000000..ecea073fa --- /dev/null +++ b/connectivity/source/inc/java/sql/Clob.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CLOB_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CLOB_HXX + +#include <java/lang/Object.hxx> +#include <com/sun/star/sdbc/XClob.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity +{ + + + //************ Class: java.sql.SQLWarning + + class java_sql_Clob : public java_lang_Object, + public ::cppu::WeakImplHelper< css::sdbc::XClob> + { + protected: + // Static data for the class + static jclass theClass; + virtual ~java_sql_Clob() override; + public: + virtual jclass getMyClass() const override; + + // A ctor that is needed for returning the object + java_sql_Clob( JNIEnv * pEnv, jobject myObj ); + + // XClob + virtual sal_Int64 SAL_CALL length( ) override; + virtual OUString SAL_CALL getSubString( sal_Int64 pos, sal_Int32 length ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( ) override; + virtual sal_Int64 SAL_CALL position( const OUString& searchstr, sal_Int32 start ) override; + virtual sal_Int64 SAL_CALL positionOfClob( const css::uno::Reference< css::sdbc::XClob >& pattern, sal_Int64 start ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CLOB_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/Connection.hxx b/connectivity/source/inc/java/sql/Connection.hxx new file mode 100644 index 000000000..cc453e6e8 --- /dev/null +++ b/connectivity/source/inc/java/sql/Connection.hxx @@ -0,0 +1,137 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CONNECTION_HXX + +#include <java/lang/Object.hxx> +#include <TConnection.hxx> +#include <connectivity/CommonTools.hxx> +#include <AutoRetrievingBase.hxx> +#include <java/sql/ConnectionLog.hxx> +#include <java/GlobalRef.hxx> + +#include <com/sun/star/beans/NamedValue.hpp> + +namespace connectivity +{ + class java_sql_Driver; + + typedef OMetaConnection java_sql_Connection_BASE; + + class java_sql_Connection : public java_sql_Connection_BASE, + public java_lang_Object, + public OAutoRetrievingBase + { + css::uno::Reference< css::uno::XComponentContext > m_xContext; + const java_sql_Driver* m_pDriver; + jobject m_pDriverobject; + jdbc::GlobalRef< jobject > + m_pDriverClassLoader; + + jclass m_Driver_theClass; + java::sql::ConnectionLog + m_aLogger; + bool m_bIgnoreDriverPrivileges; + bool m_bIgnoreCurrency; + css::uno::Any m_aCatalogRestriction; + css::uno::Any m_aSchemaRestriction; + + /** transform named parameter into unnamed one. + @param _sSQL + The SQL statement to transform. + @return + The new statement with unnamed parameters. + */ + OUString transFormPreparedStatement(const OUString& _sSQL); + void loadDriverFromProperties( + const OUString& _sDriverClass, + const OUString& _sDriverClassPath, + const css::uno::Sequence< css::beans::NamedValue >& _rSystemProperties + ); + /** load driver class path from system configuration. + @param _sDriverClass + The driver class name to look for in the configuration. + */ + OUString impl_getJavaDriverClassPath_nothrow(const OUString& _sDriverClass); + + protected: + // Static data for the class + static jclass theClass; + + virtual ~java_sql_Connection() override; + + public: + virtual jclass getMyClass() const override; + + DECLARE_SERVICE_INFO(); + // A ctor that is needed for returning the object + java_sql_Connection( const java_sql_Driver& _rDriver ); + bool construct( const OUString& url, + const css::uno::Sequence< css::beans::PropertyValue >& info); + + const css::uno::Sequence< css::beans::PropertyValue >& + getConnectionInfo() const { return m_aConnectionInfo; } + + bool isIgnoreDriverPrivilegesEnabled() const { return m_bIgnoreDriverPrivileges;} + bool isIgnoreCurrencyEnabled() const { return m_bIgnoreCurrency; } + const css::uno::Any& getCatalogRestriction() const { return m_aCatalogRestriction; } + const css::uno::Any& getSchemaRestriction() const { return m_aSchemaRestriction; } + + /** returns the instance used for logging events related to this connection + */ + const java::sql::ConnectionLog& getLogger() const { return m_aLogger; } + + /** returns the class loader which was used to load the driver class + + Usually used in conjunction with a ContextClassLoaderScope instance. + */ + const jdbc::GlobalRef< jobject >& getDriverClassLoader() const { return m_pDriverClassLoader; } + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/ConnectionLog.hxx b/connectivity/source/inc/java/sql/ConnectionLog.hxx new file mode 100644 index 000000000..780b7f27e --- /dev/null +++ b/connectivity/source/inc/java/sql/ConnectionLog.hxx @@ -0,0 +1,130 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CONNECTIONLOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CONNECTIONLOG_HXX + +#include <com/sun/star/logging/LogLevel.hpp> + +#include <rtl/ustring.hxx> + +// Strange enough, GCC requires the following forward declarations of the various +// convertLogArgToString flavors to be *before* the inclusion of comphelper/logging.hxx + +namespace com::sun::star::util +{ + struct Date; + struct Time; + struct DateTime; +} + + +namespace comphelper::log::convert +{ + + + // helpers for logging more data types than are defined in comphelper/logging.hxx + OUString convertLogArgToString( const css::util::Date& _rDate ); + OUString convertLogArgToString( const css::util::Time& _rTime ); + OUString convertLogArgToString( const css::util::DateTime& _rDateTime ); + + +} + + +#include <comphelper/logging.hxx> + +namespace connectivity +{ + namespace LogLevel = css::logging::LogLevel; +} + + +namespace connectivity::java::sql { + + typedef ::comphelper::EventLogger ConnectionLog_Base; + class ConnectionLog : public ConnectionLog_Base + { + public: + enum ObjectType + { + CONNECTION = 0, + STATEMENT, + RESULTSET, + + ObjectTypeCount = RESULTSET + 1 + }; + + private: + const sal_Int32 m_nObjectID; + + public: + /// will construct an instance of ObjectType CONNECTION + ConnectionLog( const ::comphelper::EventLogger & _rDriverLog ); + /// will create an instance with the same object ID / ObjectType as a given source instance + ConnectionLog( const ConnectionLog& _rSourceLog ); + /// will create an instance of arbitrary ObjectType + ConnectionLog( const ConnectionLog& _rSourceLog, ObjectType _eType ); + + sal_Int32 getObjectID() const { return m_nObjectID; } + + /// logs a given message, without any arguments, or source class/method names + void log( const sal_Int32 _nLogLevel, const OUString& rMessage ) + { + ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID ); + } + + template< typename ARGTYPE1 > + void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1 ) const + { + ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1 ); + } + + template< typename ARGTYPE1, typename ARGTYPE2 > + void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2 ) const + { + ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2 ); + } + + template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3 > + void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3 ) const + { + ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3 ); + } + + template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3, typename ARGTYPE4 > + void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3, ARGTYPE4 _argument4 ) const + { + ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3, _argument4 ); + } + + template< typename ARGTYPE1, typename ARGTYPE2, typename ARGTYPE3, typename ARGTYPE4, typename ARGTYPE5 > + void log( const sal_Int32 _nLogLevel, const OUString& rMessage, ARGTYPE1 _argument1, ARGTYPE2 _argument2, ARGTYPE3 _argument3, ARGTYPE4 _argument4, ARGTYPE5 _argument5 ) const + { + ConnectionLog_Base::log( _nLogLevel, rMessage, m_nObjectID, _argument1, _argument2, _argument3, _argument4, _argument5 ); + } + }; + + +} // namespace connectivity::java::sql + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_CONNECTIONLOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/DatabaseMetaData.hxx b/connectivity/source/inc/java/sql/DatabaseMetaData.hxx new file mode 100644 index 000000000..d87cd6c21 --- /dev/null +++ b/connectivity/source/inc/java/sql/DatabaseMetaData.hxx @@ -0,0 +1,218 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DATABASEMETADATA_HXX + +#include <java/lang/Object.hxx> +#include <TDatabaseMetaDataBase.hxx> + +#include <java/sql/ConnectionLog.hxx> + +namespace connectivity +{ + class java_sql_Connection; + + //************ Class: java.sql.DatabaseMetaDataDate + + + class java_sql_DatabaseMetaData : public ODatabaseMetaDataBase, + public java_lang_Object + { + java_sql_Connection* m_pConnection; + java::sql::ConnectionLog m_aLogger; + + // Static data for the class + static jclass theClass; + + public: + virtual jclass getMyClass() const override; + virtual ~java_sql_DatabaseMetaData() override; + // A ctor that is needed for returning the object + java_sql_DatabaseMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rConnection ); + + private: + + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + // cached database information + virtual OUString impl_getIdentifierQuoteString_throw( ) override; + virtual bool impl_isCatalogAtStart_throw( ) override; + virtual OUString impl_getCatalogSeparator_throw( ) override; + virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override; + virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ; + virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override; + virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ; + virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override; + virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override; + virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override; + virtual sal_Int32 impl_getMaxStatements_throw( ) override; + virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override; + virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override; + + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + + private: + bool impl_callBooleanMethod( const char* _pMethodName, jmethodID& _inout_MethodID ); + OUString impl_callStringMethod( const char* _pMethodName, jmethodID& _inout_MethodID ); + sal_Int32 impl_callIntMethod_ThrowSQL( const char* _pMethodName, jmethodID& _inout_MethodID ); + sal_Int32 impl_callIntMethod_ThrowRuntime( const char* _pMethodName, jmethodID& _inout_MethodID ); + bool impl_callBooleanMethodWithIntArg( const char* _pMethodName, jmethodID& _inout_MethodID, sal_Int32 _nArgument ); + css::uno::Reference< css::sdbc::XResultSet > + impl_callResultSetMethod( const char* _pMethodName, jmethodID& _inout_MethodID ); + css::uno::Reference< css::sdbc::XResultSet > + impl_callResultSetMethodWithStrings( const char* _pMethodName, jmethodID& _inout_MethodID, const css::uno::Any& _rCatalog, + const OUString& _rSchemaPattern, const OUString& _rLeastPattern, + const OUString* _pOptionalAdditionalString = nullptr); + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/Driver.hxx b/connectivity/source/inc/java/sql/Driver.hxx new file mode 100644 index 000000000..f50d9a3f5 --- /dev/null +++ b/connectivity/source/inc/java/sql/Driver.hxx @@ -0,0 +1,70 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DRIVER_HXX + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <comphelper/logging.hxx> + +namespace connectivity +{ + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > java_sql_Driver_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + class java_sql_Driver : public ::cppu::WeakImplHelper< css::sdbc::XDriver,css::lang::XServiceInfo> + { + css::uno::Reference<css::uno::XComponentContext> m_aContext; + ::comphelper::EventLogger m_aLogger; + + protected: + virtual ~java_sql_Driver() override; + + public: + java_sql_Driver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override ; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override ; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override ; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override ; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + + const css::uno::Reference<css::uno::XComponentContext>& getContext() const { return m_aContext; } + const ::comphelper::EventLogger& getLogger() const { return m_aLogger; } + }; + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx b/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx new file mode 100644 index 000000000..b0ab4efda --- /dev/null +++ b/connectivity/source/inc/java/sql/DriverPropertyInfo.hxx @@ -0,0 +1,44 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DRIVERPROPERTYINFO_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DRIVERPROPERTYINFO_HXX + +#include <java/lang/Object.hxx> + +namespace connectivity +{ + + +//************ Class: java.sql.DriverPropertyInfo + + class java_sql_DriverPropertyInfo : public java_lang_Object + { + protected: + // Static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_sql_DriverPropertyInfo() override; + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_DRIVERPROPERTYINFO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/JStatement.hxx b/connectivity/source/inc/java/sql/JStatement.hxx new file mode 100644 index 000000000..62cbe8154 --- /dev/null +++ b/connectivity/source/inc/java/sql/JStatement.hxx @@ -0,0 +1,236 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_JSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_JSTATEMENT_HXX + +#include <java/lang/Object.hxx> +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XBatchExecution.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> +#include <comphelper/proparrhlp.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <connectivity/CommonTools.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> + +#include <java/sql/Connection.hxx> +#include <java/sql/ConnectionLog.hxx> + +namespace connectivity +{ + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement, + css::sdbc::XWarningsSupplier, + css::util::XCancellable, + css::sdbc::XCloseable, + css::sdbc::XGeneratedResultSet, + css::sdbc::XMultipleResults> java_sql_Statement_BASE; + + //************ Class: java.sql.Statement + + class java_sql_Statement_Base : public cppu::BaseMutex, + public java_sql_Statement_BASE, + public java_lang_Object, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<java_sql_Statement_Base> + + { + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getQueryTimeOut(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getMaxFieldSize(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getMaxRows(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getResultSetConcurrency(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getResultSetType(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getFetchDirection(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getFetchSize(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OUString getCursorName(); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setQueryTimeOut(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setMaxFieldSize(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setMaxRows(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setResultSetConcurrency(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setResultSetType(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchDirection(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchSize(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setCursorName(const OUString &_par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setEscapeProcessing(bool _par0); + + protected: + css::uno::Reference< css::sdbc::XStatement> m_xGeneratedStatement; + rtl::Reference<java_sql_Connection> m_pConnection; + java::sql::ConnectionLog m_aLogger; + OUString m_sSqlStatement; + // Properties + sal_Int32 m_nResultSetConcurrency; + sal_Int32 m_nResultSetType; + bool m_bEscapeProcessing; + + + // Static data for the class + static jclass theClass; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + + virtual void createStatement(JNIEnv* _pEnv) = 0; + + virtual ~java_sql_Statement_Base() override; + + sal_Int32 impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID); + sal_Int32 impl_getProperty(const char* _pMethodName, jmethodID& _inout_MethodID,sal_Int32 _nDefault); + + public: + virtual jclass getMyClass() const override; + + // A ctor that is needed for returning the object + java_sql_Statement_Base( JNIEnv * pEnv, java_sql_Connection& _rCon ); + + sal_Int32 getStatementObjectID() const { return m_aLogger.getObjectID(); } + + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ; + virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ; + virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + //XGeneratedResultSet + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues( ) override; + + public: + using ::cppu::OPropertySetHelper::getFastPropertyValue; + }; + + class OStatement_BASE2 : public java_sql_Statement_Base + + { + public: + OStatement_BASE2(JNIEnv * pEnv, java_sql_Connection& _rCon ) : java_sql_Statement_Base( pEnv, _rCon ) {} + + // OComponentHelper + virtual void SAL_CALL disposing() override; + }; + + class java_sql_Statement : public OStatement_BASE2, + public css::sdbc::XBatchExecution, + public css::lang::XServiceInfo + { + protected: + // Static data for the class + static jclass theClass; + + virtual void createStatement(JNIEnv* _pEnv) override; + + virtual ~java_sql_Statement() override; + public: + DECLARE_SERVICE_INFO(); + virtual jclass getMyClass() const override; + + // A ctor that is needed for returning the object + java_sql_Statement( JNIEnv * pEnv, java_sql_Connection& _rCon ) : OStatement_BASE2( pEnv, _rCon){}; + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + // XBatchExecution + virtual void SAL_CALL addBatch( const OUString& sql ) override; + virtual void SAL_CALL clearBatch( ) override; + virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_JSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/PreparedStatement.hxx b/connectivity/source/inc/java/sql/PreparedStatement.hxx new file mode 100644 index 000000000..5bfc08587 --- /dev/null +++ b/connectivity/source/inc/java/sql/PreparedStatement.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_PREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_PREPAREDSTATEMENT_HXX + +#include <java/sql/JStatement.hxx> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace connectivity +{ + + //************ Class: java.sql.PreparedStatement + + + class java_sql_PreparedStatement : public OStatement_BASE2, + public css::sdbc::XPreparedStatement, + public css::sdbc::XResultSetMetaDataSupplier, + public css::sdbc::XParameters, + public css::sdbc::XPreparedBatchExecution, + public css::lang::XServiceInfo + { + protected: + // Static data for the class + static jclass theClass; + + virtual void createStatement(JNIEnv* _pEnv) override; + virtual ~java_sql_PreparedStatement() override; + public: + DECLARE_SERVICE_INFO(); + virtual jclass getMyClass() const override; + + // A ctor that is needed for returning the object + java_sql_PreparedStatement( JNIEnv * pEnv, java_sql_Connection& _rCon,const OUString& sql ); + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + virtual sal_Bool SAL_CALL execute( ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + // XPreparedBatchExecution + virtual void SAL_CALL addBatch( ) override; + virtual void SAL_CALL clearBatch( ) override; + virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + + public: + using java_sql_Statement_Base::executeQuery; + using java_sql_Statement_Base::executeUpdate; + using java_sql_Statement_Base::execute; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_PREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/Ref.hxx b/connectivity/source/inc/java/sql/Ref.hxx new file mode 100644 index 000000000..eb658925f --- /dev/null +++ b/connectivity/source/inc/java/sql/Ref.hxx @@ -0,0 +1,51 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_REF_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_REF_HXX + +#include <java/lang/Object.hxx> +#include <com/sun/star/sdbc/XRef.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity +{ + + //************ Class: java.sql.Ref + + class java_sql_Ref : public java_lang_Object, + public ::cppu::WeakImplHelper< css::sdbc::XRef> + { + protected: + // Static data for the class + static jclass theClass; + virtual ~java_sql_Ref() override; + public: + virtual jclass getMyClass() const override; + + // A ctor that is needed for returning the object + java_sql_Ref( JNIEnv * pEnv, jobject myObj ); + + // XRef + virtual OUString SAL_CALL getBaseTypeName( ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_REF_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/ResultSet.hxx b/connectivity/source/inc/java/sql/ResultSet.hxx new file mode 100644 index 000000000..e5e0155ff --- /dev/null +++ b/connectivity/source/inc/java/sql/ResultSet.hxx @@ -0,0 +1,212 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_RESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_RESULTSET_HXX + +#include <java/lang/Object.hxx> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <cppuhelper/compbase.hxx> +#include <comphelper/proparrhlp.hxx> +#include <connectivity/CommonTools.hxx> +#include <java/sql/JStatement.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <java/sql/ConnectionLog.hxx> + +namespace connectivity +{ + + /* + ** java_sql_ResultSet + */ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate, + css::lang::XServiceInfo> java_sql_ResultSet_BASE; + + class java_sql_Connection; + class java_sql_ResultSet : public cppu::BaseMutex, + public java_sql_ResultSet_BASE, + public java_lang_Object, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<java_sql_ResultSet> + { + css::uno::Reference< css::uno::XInterface> m_xStatement; + java::sql::ConnectionLog m_aLogger; + java_sql_Connection* m_pConnection; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getResultSetConcurrency() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getResultSetType() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getFetchDirection() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getFetchSize() const; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OUString getCursorName() const; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchDirection(sal_Int32 _par0); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setFetchSize(sal_Int32 _par0); + protected: + // Static data for the class + static jclass theClass; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + virtual ~java_sql_ResultSet() override; + public: + DECLARE_SERVICE_INFO(); + virtual jclass getMyClass() const override; + // A ctor that is needed for returning the object + java_sql_ResultSet( JNIEnv * pEnv, jobject myObj, const java::sql::ConnectionLog& _rParentLogger,java_sql_Connection& _rConnection, + java_sql_Statement_Base* pStmt = nullptr ); + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + + public: + using ::cppu::OPropertySetHelper::getFastPropertyValue; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_RESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/ResultSetMetaData.hxx b/connectivity/source/inc/java/sql/ResultSetMetaData.hxx new file mode 100644 index 000000000..bc96fdf4b --- /dev/null +++ b/connectivity/source/inc/java/sql/ResultSetMetaData.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_RESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_RESULTSETMETADATA_HXX + +#include <java/lang/Object.hxx> +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity +{ + + //************ Class: java.sql.ResultSetMetaData + + class java_sql_Connection; + class java_sql_ResultSetMetaData final : public ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData>, + public java_lang_Object + { + java_sql_Connection* m_pConnection; + sal_Int32 m_nColumnCount; + + // Static data for the class + static jclass theClass; + virtual ~java_sql_ResultSetMetaData() override; + public: + virtual jclass getMyClass() const override; + + // A ctor that is needed for returning the object + java_sql_ResultSetMetaData( JNIEnv * pEnv, jobject myObj, java_sql_Connection& _rCon ); + + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_RESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/SQLException.hxx b/connectivity/source/inc/java/sql/SQLException.hxx new file mode 100644 index 000000000..88a147faa --- /dev/null +++ b/connectivity/source/inc/java/sql/SQLException.hxx @@ -0,0 +1,58 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_SQLEXCEPTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_SQLEXCEPTION_HXX + +#include <java/lang/Exception.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> + +namespace connectivity +{ + //************ Class: java.sql.SQLException + + class java_sql_SQLException_BASE; + class java_sql_SQLException : public css::sdbc::SQLException + { + public: + // A ctor that is needed for returning the object + java_sql_SQLException( const java_sql_SQLException_BASE& _rException,const css::uno::Reference< css::uno::XInterface> & _rContext); + }; + + class java_sql_SQLException_BASE : public java_lang_Exception + { + protected: + // Static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_sql_SQLException_BASE() override; + // A ctor that is needed for returning the object + java_sql_SQLException_BASE( JNIEnv * pEnv, jobject myObj ); + + OUString getSQLState() const; + sal_Int32 getErrorCode() const; + css::sdbc::SQLException getNextException() const; + + static jclass st_getMyClass(); + }; + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_SQLEXCEPTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/SQLWarning.hxx b/connectivity/source/inc/java/sql/SQLWarning.hxx new file mode 100644 index 000000000..68a83f463 --- /dev/null +++ b/connectivity/source/inc/java/sql/SQLWarning.hxx @@ -0,0 +1,51 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_SQLWARNING_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_SQLWARNING_HXX + +#include <java/sql/SQLException.hxx> + +namespace connectivity +{ + //************ Class: java.sql.SQLWarning + + class java_sql_SQLWarning_BASE : public java_sql_SQLException_BASE + { + protected: + // Static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_sql_SQLWarning_BASE() override; + // A ctor that is needed for returning the object + java_sql_SQLWarning_BASE( JNIEnv * pEnv, jobject myObj ) : java_sql_SQLException_BASE( pEnv, myObj ){} + + }; + + class java_sql_SQLWarning : public java_sql_SQLException + { + public: + java_sql_SQLWarning(const java_sql_SQLWarning_BASE& _rW,const css::uno::Reference< css::uno::XInterface> & _rContext) + : java_sql_SQLException(_rW,_rContext) {} + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_SQLWARNING_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/sql/Timestamp.hxx b/connectivity/source/inc/java/sql/Timestamp.hxx new file mode 100644 index 000000000..0d41d46d6 --- /dev/null +++ b/connectivity/source/inc/java/sql/Timestamp.hxx @@ -0,0 +1,90 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_TIMESTAMP_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_TIMESTAMP_HXX + +#include <java/util/Date.hxx> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> + + +namespace connectivity +{ + + //************ Class: java.sql.Date + + + class java_sql_Date : public java_util_Date + { + protected: + // static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_sql_Date() override; + // A ctor that is needed for returning the object + java_sql_Date( JNIEnv * pEnv, jobject myObj ) : java_util_Date(pEnv,myObj){} + java_sql_Date( const css::util::Date& _rOut ); + + operator css::util::Date(); + static jclass st_getMyClass(); + }; + + + //************ Class: java.sql.Time + + + class java_sql_Time : public java_util_Date + { + protected: + // static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_sql_Time() override; + // A ctor that is needed for returning the object + java_sql_Time( JNIEnv * pEnv, jobject myObj ) : java_util_Date( pEnv, myObj ){} + java_sql_Time( const css::util::Time& _rOut ); + operator css::util::Time(); + static jclass st_getMyClass(); + }; + + + //************ Class: java.sql.Timestamp + + class java_sql_Timestamp : public java_util_Date + { + protected: + // static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_sql_Timestamp() override; + // A ctor that is needed for returning the object + java_sql_Timestamp( JNIEnv * pEnv, jobject myObj ) : java_util_Date( pEnv, myObj ){} + java_sql_Timestamp( const css::util::DateTime& _rOut); + operator css::util::DateTime(); + + static jclass st_getMyClass(); + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_SQL_TIMESTAMP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/tools.hxx b/connectivity/source/inc/java/tools.hxx new file mode 100644 index 000000000..aa7cb20ca --- /dev/null +++ b/connectivity/source/inc/java/tools.hxx @@ -0,0 +1,58 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_TOOLS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_TOOLS_HXX + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/uno/Sequence.h> + +#include <jni.h> + +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/io/XInputStream.hpp> + + +namespace connectivity +{ + + jstring convertwchar_tToJavaString(JNIEnv *pEnv,const OUString& Temp); + OUString JavaString2String(JNIEnv *pEnv,jstring Str); + class java_util_Properties; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + std::unique_ptr<java_util_Properties> createStringPropertyArray(const css::uno::Sequence< css::beans::PropertyValue >& info ); + + jobject convertTypeMapToJavaMap(const css::uno::Reference< css::container::XNameAccess > & _rMap); + + /** return if an exception occurred + the exception will be cleared. + @param pEnv + The native java env + */ + bool isExceptionOccurred(JNIEnv *pEnv); + + jobject createByteInputStream(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length); + jobject createCharArrayReader(const css::uno::Reference< css::io::XInputStream >& x,sal_Int32 length); +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_TOOLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/util/Date.hxx b/connectivity/source/inc/java/util/Date.hxx new file mode 100644 index 000000000..9c2e8a3ee --- /dev/null +++ b/connectivity/source/inc/java/util/Date.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_UTIL_DATE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_UTIL_DATE_HXX + +#include <java/lang/Object.hxx> +//#include <com/sun/star/util/Date.hpp> + +namespace connectivity +{ + + + //************ Class: java.util.Date + + + class java_util_Date : public java_lang_Object + { + protected: + // Static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_util_Date() override; + // A ctor that is needed for returning the object + java_util_Date( JNIEnv * pEnv, jobject myObj ) : java_lang_Object( pEnv, myObj ){} + }; +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_UTIL_DATE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/java/util/Property.hxx b/connectivity/source/inc/java/util/Property.hxx new file mode 100644 index 000000000..f7835e5f1 --- /dev/null +++ b/connectivity/source/inc/java/util/Property.hxx @@ -0,0 +1,41 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_UTIL_PROPERTY_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_UTIL_PROPERTY_HXX + +#include <java/lang/Object.hxx> + +namespace connectivity +{ + class java_util_Properties : public java_lang_Object + { + protected: + // Static data for the class + static jclass theClass; + public: + virtual jclass getMyClass() const override; + virtual ~java_util_Properties() override; + java_util_Properties( ); + void setProperty(const OUString& key, const OUString& value); + }; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_JAVA_UTIL_PROPERTY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/mysql/YCatalog.hxx b/connectivity/source/inc/mysql/YCatalog.hxx new file mode 100644 index 000000000..35dd2a3cd --- /dev/null +++ b/connectivity/source/inc/mysql/YCatalog.hxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YCATALOG_HXX + +#include <sdbcx/VCatalog.hxx> + +namespace connectivity +{ + namespace mysql + { + // please don't name the class the same name as in another namespaces + // some compilers have problems with this task as I noticed on windows + class OMySQLCatalog : public connectivity::sdbcx::OCatalog + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + + /** calls XDatabaseMetaData::getTables. + @param _sKindOfObject + The type of tables to be fetched. + @param _rNames + The container for the names to be filled. <OUT/> + */ + void refreshObjects(const css::uno::Sequence< OUString >& _sKindOfObject,::std::vector< OUString>& _rNames); + + public: + // implementation of the pure virtual methods + virtual void refreshTables() override; + virtual void refreshViews() override ; + virtual void refreshGroups() override; + virtual void refreshUsers() override ; + + public: + OMySQLCatalog(const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + + sdbcx::OCollection* getPrivateTables() const { return m_pTables.get();} + sdbcx::OCollection* getPrivateViews() const { return m_pViews.get(); } + const css::uno::Reference< css::sdbc::XConnection >& getConnection() const { return m_xConnection; } + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + // ::cppu::OComponentHelper + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/mysql/YColumns.hxx b/connectivity/source/inc/mysql/YColumns.hxx new file mode 100644 index 000000000..9e2d49535 --- /dev/null +++ b/connectivity/source/inc/mysql/YColumns.hxx @@ -0,0 +1,60 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YCOLUMNS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YCOLUMNS_HXX +#include <connectivity/TColumnsHelper.hxx> +#include <connectivity/sdbcx/VColumn.hxx> + +namespace connectivity +{ + namespace mysql + { + class OMySQLColumns : public OColumnsHelper + { + protected: + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + public: + OMySQLColumns( ::cppu::OWeakObject& _rParent + ,::osl::Mutex& _rMutex + ,const ::std::vector< OUString> &_rVector + ); + }; + + class OMySQLColumn; + typedef ::comphelper::OIdPropertyArrayUsageHelper<OMySQLColumn> OMySQLColumn_PROP; + + class OMySQLColumn : public sdbcx::OColumn, + public OMySQLColumn_PROP + { + OUString m_sAutoIncrement; + protected: + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + public: + OMySQLColumn(); + virtual void construct() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YCOLUMNS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/mysql/YDriver.hxx b/connectivity/source/inc/mysql/YDriver.hxx new file mode 100644 index 000000000..a44f66048 --- /dev/null +++ b/connectivity/source/inc/mysql/YDriver.hxx @@ -0,0 +1,117 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YDRIVER_HXX + +#include <sal/config.h> + +#include <map> + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <connectivity/CommonTools.hxx> + + +namespace connectivity +{ + + + class OMetaConnection; + + namespace mysql + { + /// @throws css::uno::Exception + css::uno::Reference< css::uno::XInterface > ODriverDelegator_CreateInstance(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxMSF); + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver + , css::sdbcx::XDataDefinitionSupplier + , css::lang::XServiceInfo + > ODriverDelegator_BASE; + + typedef std::pair< css::uno::WeakReferenceHelper,OMetaConnection*> TWeakConnectionPair; + typedef std::pair< css::uno::WeakReferenceHelper,TWeakConnectionPair> TWeakPair; + typedef std::vector< TWeakPair > TWeakPairVector; + typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > TJDBCDrivers; + + /** delegates all calls to the original driver and extend the existing one with the SDBCX layer. + + */ + class ODriverDelegator : public ::cppu::BaseMutex + ,public ODriverDelegator_BASE + { + TJDBCDrivers m_aJdbcDrivers; // all jdbc drivers + TWeakPairVector m_aConnections; // vector containing a list + // of all the Connection objects + // for this Driver + css::uno::Reference< css::sdbc::XDriver > m_xODBCDriver; + css::uno::Reference< css::sdbc::XDriver > m_xNativeDriver; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + /** load the driver we want to delegate. + The <member>m_xODBCDriver</member> or <member>m_xDBCDriver</member> may be <NULL/> if the driver could not be loaded. + @param url + The URL. + @param info + The property info contains which driver we have to delegate. + @return + The driver which was currently selected. + */ + css::uno::Reference< css::sdbc::XDriver > loadDriver( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ); + + public: + /** creates a new delegator for a mysql driver + */ + ODriverDelegator(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + // XServiceInfo + DECLARE_SERVICE_INFO(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + + // XDataDefinitionSupplier + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByConnection( const css::uno::Reference< css::sdbc::XConnection >& connection ) override; + virtual css::uno::Reference< css::sdbcx::XTablesSupplier > SAL_CALL getDataDefinitionByURL( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + protected: + /// dtor + virtual ~ODriverDelegator() override; + // OComponentHelper + virtual void SAL_CALL disposing() override; + }; + } + + +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YDRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/mysql/YTable.hxx b/connectivity/source/inc/mysql/YTable.hxx new file mode 100644 index 000000000..00739de5c --- /dev/null +++ b/connectivity/source/inc/mysql/YTable.hxx @@ -0,0 +1,115 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YTABLE_HXX + +#include <connectivity/TTableHelper.hxx> +#include <comphelper/IdPropArrayHelper.hxx> + +namespace connectivity +{ + namespace mysql + { + + class OMySQLTable; + typedef ::comphelper::OIdPropertyArrayUsageHelper< OMySQLTable > OMySQLTable_PROP; + class OMySQLTable : public OTableHelper + ,public OMySQLTable_PROP + { + sal_Int32 m_nPrivileges; // we have to set our privileges by our own + + /** executes the statement. + @param _rStatement + The statement to execute. + */ + void executeStatement(const OUString& _rStatement ); + protected: + + /** creates the column collection for the table + @param _rNames + The column names. + */ + virtual sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override; + + /** creates the key collection for the table + @param _rNames + The key names. + */ + virtual sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override; + + /** creates the index collection for the table + @param _rNames + The index names. + */ + virtual sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override; + + /** Returns always "RENAME TABLE " even for views. + * + * \return The start of the rename statement. + * @see http://dev.mysql.com/doc/refman/5.1/de/rename-table.html + */ + virtual OUString getRenameStart() const override; + + /** used to implement the creation of the array helper which is shared amongst all instances of the class. + This method needs to be implemented in derived classes. + <BR> + The method gets called with s_aMutex acquired. + @return a pointer to the newly created array helper. Must not be NULL. + */ + virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + public: + OMySQLTable( sdbcx::OCollection* _pTables, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + OMySQLTable( sdbcx::OCollection* _pTables, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description, + const OUString& SchemaName, + const OUString& CatalogName, + sal_Int32 _nPrivileges + ); + + // ODescriptor + virtual void construct() override; + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + // XAlterTable + virtual void SAL_CALL alterColumnByName( const OUString& colName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + /** returns the ALTER TABLE XXX statement + */ + OUString getAlterTableColumnPart() const; + + // some methods to alter table structures + void alterColumnType(sal_Int32 nNewType,const OUString& _rColName,const css::uno::Reference< css::beans::XPropertySet >& _xDescriptor); + void alterDefaultValue(const OUString& _sNewDefault,const OUString& _rColName); + void dropDefaultValue(const OUString& _sNewDefault); + + virtual OUString getTypeCreatePattern() const override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/mysql/YTables.hxx b/connectivity/source/inc/mysql/YTables.hxx new file mode 100644 index 000000000..5c960f5f0 --- /dev/null +++ b/connectivity/source/inc/mysql/YTables.hxx @@ -0,0 +1,66 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YTABLES_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <SQLStatementHelper.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +namespace connectivity +{ + namespace mysql + { + class OTables final : public sdbcx::OCollection, + public ::dbtools::ISQLStatementHelper + { + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + + void createTable( const css::uno::Reference< css::beans::XPropertySet >& descriptor ); + virtual OUString getNameForObject(const sdbcx::ObjectType& _xObject) override; + public: + OTables(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + ,m_xMetaData(_rMetaData) + {} + + // only the name is identical to ::cppu::OComponentHelper + virtual void disposing() override; + + // XDrop + void appendNew(const OUString& _rsNewTable); + + /** convert the sql statement to fit MySQL notation + @param _sSql in/out + */ + static OUString adjustSQL(const OUString& _sSql); + + // ISQLStatementHelper + virtual void addComment(const css::uno::Reference< css::beans::XPropertySet >& descriptor,OUStringBuffer& _rOut) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YTABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/mysql/YUser.hxx b/connectivity/source/inc/mysql/YUser.hxx new file mode 100644 index 000000000..3377d13fc --- /dev/null +++ b/connectivity/source/inc/mysql/YUser.hxx @@ -0,0 +1,77 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YUSER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YUSER_HXX + +#include <sdbcx/VUser.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> + +namespace connectivity +{ + namespace mysql + { + typedef connectivity::sdbcx::OUser OUser_TYPEDEF; + + class OMySQLUser : public OUser_TYPEDEF + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + + static OUString getPrivilegeString(sal_Int32 nRights); + // return the privileges and additional the grant rights + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void findPrivilegesAndGrantPrivileges(const OUString& objName, sal_Int32 objType,sal_Int32& nRights,sal_Int32& nRightsWithGrant); + public: + virtual void refreshGroups() override; + public: + OMySQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + OMySQLUser( const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const OUString& Name); + + // XUser + virtual void SAL_CALL changePassword( const OUString& objPassword, const OUString& newPassword ) override; + // XAuthorizable + virtual sal_Int32 SAL_CALL getPrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual sal_Int32 SAL_CALL getGrantablePrivileges( const OUString& objName, sal_Int32 objType ) override; + virtual void SAL_CALL grantPrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + virtual void SAL_CALL revokePrivileges( const OUString& objName, sal_Int32 objType, sal_Int32 objPrivileges ) override; + }; + + class OUserExtend; + typedef ::comphelper::OPropertyArrayUsageHelper<OUserExtend> OUserExtend_PROP; + + class OUserExtend : public OMySQLUser, + public OUserExtend_PROP + { + OUString m_Password; + protected: + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + public: + OUserExtend(const css::uno::Reference< css::sdbc::XConnection >& _xConnection); + + virtual void construct() override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YUSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/mysql/YUsers.hxx b/connectivity/source/inc/mysql/YUsers.hxx new file mode 100644 index 000000000..69695ca64 --- /dev/null +++ b/connectivity/source/inc/mysql/YUsers.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YUSERS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YUSERS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XConnection.hpp> +namespace connectivity +{ + namespace sdbcx + { + class IRefreshableUsers; + } + namespace mysql + { + class OUsers : public sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + connectivity::sdbcx::IRefreshableUsers* m_pParent; + public: + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual void impl_refresh() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos,const OUString& _sElementName) override; + public: + OUsers( ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector, + const css::uno::Reference< css::sdbc::XConnection >& _xConnection, + connectivity::sdbcx::IRefreshableUsers* _pParent); + }; + } +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YUSERS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/mysql/YViews.hxx b/connectivity/source/inc/mysql/YViews.hxx new file mode 100644 index 000000000..05c47edcb --- /dev/null +++ b/connectivity/source/inc/mysql/YViews.hxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YVIEWS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YVIEWS_HXX + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +namespace connectivity +{ + namespace mysql + { + class OViews final : public sdbcx::OCollection + { + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + bool m_bInDrop; + virtual sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + + void createView( const css::uno::Reference< css::beans::XPropertySet >& descriptor ); + public: + OViews(const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rMetaData,::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector< OUString> &_rVector) : sdbcx::OCollection(_rParent, true, _rMutex, _rVector) + ,m_xMetaData(_rMetaData) + ,m_bInDrop(false) + {} + + // only the name is identical to ::cppu::OComponentHelper + virtual void disposing() override; + + void dropByNameImpl(const OUString& elementName); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_MYSQL_YVIEWS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/OBoundParam.hxx b/connectivity/source/inc/odbc/OBoundParam.hxx new file mode 100644 index 000000000..0616760bf --- /dev/null +++ b/connectivity/source/inc/odbc/OBoundParam.hxx @@ -0,0 +1,131 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OBOUNDPARAM_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OBOUNDPARAM_HXX + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <odbc/odbcbasedllapi.hxx> + +namespace connectivity +{ + namespace odbc + { + class OOO_DLLPUBLIC_ODBCBASE OBoundParam + { + + public: + OBoundParam() + : binaryData(nullptr) + , paramLength(0) + , paramInputStreamLen(0) + { + } + ~OBoundParam() + { + free(binaryData); + } + + // allocBindDataBuffer + // Allocates and returns a new bind data buffer of the specified + // length + + void* allocBindDataBuffer (sal_Int32 bufLen) + { + // Reset the input stream and sequence, we are doing a new bind + setInputStream (nullptr, 0); + aSequence.realloc(0); + + free(binaryData); + binaryData = (bufLen > 0) ? malloc(bufLen) : nullptr; + + return binaryData; + } + + + // getBindLengthBuffer + // Returns the length buffer to be used when binding to a parameter + + SQLLEN& getBindLengthBuffer () + { + return paramLength; + } + + + // setInputStream + // Sets the input stream for the bound parameter + + void setInputStream(const css::uno::Reference< css::io::XInputStream>& inputStream, + sal_Int32 len) + { + paramInputStream = inputStream; + paramInputStreamLen = len; + } + + void setSequence(const css::uno::Sequence< sal_Int8 >& _aSequence) + { + aSequence = _aSequence; + } + + + // getInputStream + // Gets the input stream for the bound parameter + + const css::uno::Reference< css::io::XInputStream>& getInputStream () const + { + return paramInputStream; + } + + + // getInputStreamLen + // Gets the input stream length for the bound parameter + + sal_Int32 getInputStreamLen () const + { + return paramInputStreamLen; + } + + + private: + + // Data attributes + + + void *binaryData; // Storage area to be used + // when binding the parameter + + SQLLEN paramLength; // Storage area to be used + // for the bound length of the + // parameter. Note that this + // data is in native format. + + css::uno::Reference< css::io::XInputStream> paramInputStream; + css::uno::Sequence< sal_Int8 > aSequence; + // When an input stream is + // bound to a parameter, a + // reference to the input stream is saved + // until not needed anymore. + + sal_Int32 paramInputStreamLen; // Length of input stream + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OBOUNDPARAM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/OConnection.hxx b/connectivity/source/inc/odbc/OConnection.hxx new file mode 100644 index 000000000..cb05d7373 --- /dev/null +++ b/connectivity/source/inc/odbc/OConnection.hxx @@ -0,0 +1,129 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OCONNECTION_HXX + +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <connectivity/odbc.hxx> +#include <odbc/odbcbasedllapi.hxx> +#include <connectivity/CommonTools.hxx> +#include <TConnection.hxx> +#include <OTypeInfo.hxx> +#include <odbc/OTools.hxx> +#include <cppuhelper/weakref.hxx> +#include <AutoRetrievingBase.hxx> +#include <osl/module.h> + + +#include <map> + +namespace connectivity +{ + namespace odbc + { + class ODBCDriver; + + typedef connectivity::OMetaConnection OConnection_BASE; + typedef std::vector< ::connectivity::OTypeInfo> TTypeInfoVector; + + class OOO_DLLPUBLIC_ODBCBASE OConnection final : + public OConnection_BASE, + public OAutoRetrievingBase + { + // Data attributes + + std::map< SQLHANDLE, rtl::Reference<OConnection>> m_aConnections; // holds all connections which are need for several statements + + + OUString m_sUser; // the user name + rtl::Reference<ODBCDriver> + m_xDriver; // Pointer to the owning + // driver object + + SQLHANDLE m_aConnectionHandle; + SQLHANDLE m_pDriverHandleCopy; // performance reason + sal_Int32 m_nStatementCount; + bool m_bClosed; + bool m_bUseCatalog; // should we use the catalog on filebased databases + bool m_bUseOldDateFormat; + bool m_bIgnoreDriverPrivileges; + bool m_bPreventGetVersionColumns; // #i60273# + bool m_bReadOnly; + + + SQLRETURN OpenConnection(const OUString& aConnectStr,sal_Int32 nTimeOut, bool bSilent); + + public: + oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const; + /// @throws css::sdbc::SQLException + SQLRETURN Construct( const OUString& url,const css::uno::Sequence< css::beans::PropertyValue >& info); + + OConnection(const SQLHANDLE _pDriverHandle,ODBCDriver* _pDriver); + // OConnection(const SQLHANDLE _pConnectionHandle); + virtual ~OConnection() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual void SAL_CALL setCatalog( const OUString& catalog ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + + SQLHANDLE getConnection() { return m_aConnectionHandle; } + + // should we use the catalog on filebased databases + bool isCatalogUsed() const { return m_bUseCatalog; } + bool isIgnoreDriverPrivilegesEnabled() const { return m_bIgnoreDriverPrivileges; } + bool preventGetVersionColumns() const { return m_bPreventGetVersionColumns; } + bool useOldDateFormat() const { return m_bUseOldDateFormat; } + ODBCDriver* getDriver() const { return m_xDriver.get();} + + SQLHANDLE createStatementHandle(); + // close and free the handle and set it to SQL_NULLHANDLE + void freeStatementHandle(SQLHANDLE& _pHandle); + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/ODatabaseMetaData.hxx b/connectivity/source/inc/odbc/ODatabaseMetaData.hxx new file mode 100644 index 000000000..c4ad2c075 --- /dev/null +++ b/connectivity/source/inc/odbc/ODatabaseMetaData.hxx @@ -0,0 +1,207 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODATABASEMETADATA_HXX + +#include <odbc/OConnection.hxx> +#include <odbc/odbcbasedllapi.hxx> +#include <TDatabaseMetaDataBase.hxx> + +namespace connectivity +{ + namespace odbc + { + + //************ Class: ODatabaseMetaData + + + class OOO_DLLPUBLIC_ODBCBASE ODatabaseMetaData final : + public ODatabaseMetaDataBase + { + SQLHANDLE m_aConnectionHandle; + OConnection* m_pConnection; + bool m_bUseCatalog; + + // cached database information + virtual OUString impl_getIdentifierQuoteString_throw( ) override; + virtual bool impl_isCatalogAtStart_throw( ) override; + virtual OUString impl_getCatalogSeparator_throw( ) override; + virtual bool impl_supportsCatalogsInTableDefinitions_throw( ) override; + virtual bool impl_supportsSchemasInTableDefinitions_throw( ) override ; + virtual bool impl_supportsCatalogsInDataManipulation_throw( ) override; + virtual bool impl_supportsSchemasInDataManipulation_throw( ) override ; + virtual bool impl_supportsMixedCaseQuotedIdentifiers_throw( ) override ; + virtual bool impl_supportsAlterTableWithAddColumn_throw( ) override; + virtual bool impl_supportsAlterTableWithDropColumn_throw( ) override; + virtual sal_Int32 impl_getMaxStatements_throw( ) override; + virtual sal_Int32 impl_getMaxTablesInSelect_throw( ) override; + virtual bool impl_storesMixedCaseQuotedIdentifiers_throw( ) override; + OUString getURLImpl(); + virtual css::uno::Reference< css::sdbc::XResultSet > impl_getTypeInfo_throw() override; + virtual ~ODatabaseMetaData() override; + + public: + ODatabaseMetaData(const SQLHANDLE _pHandle,OConnection* _pCon); + + // XDatabaseMetaData + virtual sal_Bool SAL_CALL allProceduresAreCallable( ) override; + virtual sal_Bool SAL_CALL allTablesAreSelectable( ) override; + virtual OUString SAL_CALL getURL( ) override; + virtual OUString SAL_CALL getUserName( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedHigh( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedLow( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtStart( ) override; + virtual sal_Bool SAL_CALL nullsAreSortedAtEnd( ) override; + virtual OUString SAL_CALL getDatabaseProductName( ) override; + virtual OUString SAL_CALL getDatabaseProductVersion( ) override; + virtual OUString SAL_CALL getDriverName( ) override; + virtual OUString SAL_CALL getDriverVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getDriverMinorVersion( ) override; + virtual sal_Bool SAL_CALL usesLocalFiles( ) override; + virtual sal_Bool SAL_CALL usesLocalFilePerTable( ) override; + virtual sal_Bool SAL_CALL supportsMixedCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesUpperCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesMixedCaseIdentifiers( ) override; + + virtual sal_Bool SAL_CALL storesUpperCaseQuotedIdentifiers( ) override; + virtual sal_Bool SAL_CALL storesLowerCaseQuotedIdentifiers( ) override; + + virtual OUString SAL_CALL getSQLKeywords( ) override; + virtual OUString SAL_CALL getNumericFunctions( ) override; + virtual OUString SAL_CALL getStringFunctions( ) override; + virtual OUString SAL_CALL getSystemFunctions( ) override; + virtual OUString SAL_CALL getTimeDateFunctions( ) override; + virtual OUString SAL_CALL getSearchStringEscape( ) override; + virtual OUString SAL_CALL getExtraNameCharacters( ) override; + virtual sal_Bool SAL_CALL supportsColumnAliasing( ) override; + virtual sal_Bool SAL_CALL nullPlusNonNullIsNull( ) override; + virtual sal_Bool SAL_CALL supportsTypeConversion( ) override; + virtual sal_Bool SAL_CALL supportsConvert( sal_Int32 fromType, sal_Int32 toType ) override; + virtual sal_Bool SAL_CALL supportsTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsDifferentTableCorrelationNames( ) override; + virtual sal_Bool SAL_CALL supportsExpressionsInOrderBy( ) override; + virtual sal_Bool SAL_CALL supportsOrderByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupBy( ) override; + virtual sal_Bool SAL_CALL supportsGroupByUnrelated( ) override; + virtual sal_Bool SAL_CALL supportsGroupByBeyondSelect( ) override; + virtual sal_Bool SAL_CALL supportsLikeEscapeClause( ) override; + virtual sal_Bool SAL_CALL supportsMultipleResultSets( ) override; + virtual sal_Bool SAL_CALL supportsMultipleTransactions( ) override; + virtual sal_Bool SAL_CALL supportsNonNullableColumns( ) override; + virtual sal_Bool SAL_CALL supportsMinimumSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsCoreSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsExtendedSQLGrammar( ) override; + virtual sal_Bool SAL_CALL supportsANSI92EntryLevelSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92IntermediateSQL( ) override; + virtual sal_Bool SAL_CALL supportsANSI92FullSQL( ) override; + virtual sal_Bool SAL_CALL supportsIntegrityEnhancementFacility( ) override; + virtual sal_Bool SAL_CALL supportsOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsFullOuterJoins( ) override; + virtual sal_Bool SAL_CALL supportsLimitedOuterJoins( ) override; + virtual OUString SAL_CALL getSchemaTerm( ) override; + virtual OUString SAL_CALL getProcedureTerm( ) override; + virtual OUString SAL_CALL getCatalogTerm( ) override; + + virtual sal_Bool SAL_CALL supportsSchemasInProcedureCalls( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsSchemasInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInProcedureCalls( ) override; + + virtual sal_Bool SAL_CALL supportsCatalogsInIndexDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsCatalogsInPrivilegeDefinitions( ) override; + virtual sal_Bool SAL_CALL supportsPositionedDelete( ) override; + virtual sal_Bool SAL_CALL supportsPositionedUpdate( ) override; + virtual sal_Bool SAL_CALL supportsSelectForUpdate( ) override; + virtual sal_Bool SAL_CALL supportsStoredProcedures( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInComparisons( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInExists( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInIns( ) override; + virtual sal_Bool SAL_CALL supportsSubqueriesInQuantifieds( ) override; + virtual sal_Bool SAL_CALL supportsCorrelatedSubqueries( ) override; + virtual sal_Bool SAL_CALL supportsUnion( ) override; + virtual sal_Bool SAL_CALL supportsUnionAll( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenCursorsAcrossRollback( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossCommit( ) override; + virtual sal_Bool SAL_CALL supportsOpenStatementsAcrossRollback( ) override; + virtual sal_Int32 SAL_CALL getMaxBinaryLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCharLiteralLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInGroupBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInIndex( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInOrderBy( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInSelect( ) override; + virtual sal_Int32 SAL_CALL getMaxColumnsInTable( ) override; + virtual sal_Int32 SAL_CALL getMaxConnections( ) override; + virtual sal_Int32 SAL_CALL getMaxCursorNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxIndexLength( ) override; + virtual sal_Int32 SAL_CALL getMaxSchemaNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxProcedureNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxCatalogNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxRowSize( ) override; + virtual sal_Bool SAL_CALL doesMaxRowSizeIncludeBlobs( ) override; + virtual sal_Int32 SAL_CALL getMaxStatementLength( ) override; + virtual sal_Int32 SAL_CALL getMaxTableNameLength( ) override; + virtual sal_Int32 SAL_CALL getMaxUserNameLength( ) override; + virtual sal_Int32 SAL_CALL getDefaultTransactionIsolation( ) override; + virtual sal_Bool SAL_CALL supportsTransactions( ) override; + virtual sal_Bool SAL_CALL supportsTransactionIsolationLevel( sal_Int32 level ) override; + virtual sal_Bool SAL_CALL supportsDataDefinitionAndDataManipulationTransactions( ) override; + virtual sal_Bool SAL_CALL supportsDataManipulationTransactionsOnly( ) override; + virtual sal_Bool SAL_CALL dataDefinitionCausesTransactionCommit( ) override; + virtual sal_Bool SAL_CALL dataDefinitionIgnoredInTransactions( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& procedureNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTables( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getSchemas( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCatalogs( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTableTypes( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumns( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, const OUString& table, const OUString& columnNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getTablePrivileges( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& tableNamePattern ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Int32 scope, sal_Bool nullable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getVersionColumns( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getPrimaryKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getImportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getExportedKeys( const css::uno::Any& catalog, const OUString& schema, const OUString& table ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getCrossReference( const css::uno::Any& primaryCatalog, const OUString& primarySchema, const OUString& primaryTable, const css::uno::Any& foreignCatalog, const OUString& foreignSchema, const OUString& foreignTable ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getIndexInfo( const css::uno::Any& catalog, const OUString& schema, const OUString& table, sal_Bool unique, sal_Bool approximate ) override; + virtual sal_Bool SAL_CALL supportsResultSetType( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 concurrency ) override; + virtual sal_Bool SAL_CALL ownUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL ownInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersUpdatesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersDeletesAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL othersInsertsAreVisible( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL updatesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL deletesAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL insertsAreDetected( sal_Int32 setType ) override; + virtual sal_Bool SAL_CALL supportsBatchUpdates( ) override; + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getUDTs( const css::uno::Any& catalog, const OUString& schemaPattern, const OUString& typeNamePattern, const css::uno::Sequence< sal_Int32 >& types ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx b/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx new file mode 100644 index 000000000..64d548a76 --- /dev/null +++ b/connectivity/source/inc/odbc/ODatabaseMetaDataResultSet.hxx @@ -0,0 +1,263 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODATABASEMETADATARESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODATABASEMETADATARESULTSET_HXX + +#include <com/sun/star/sdbc/ResultSetType.hpp> +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/ResultSetConcurrency.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <comphelper/proparrhlp.hxx> +#include <odbc/OStatement.hxx> +#include <odbc/ODatabaseMetaData.hxx> +#include <odbc/odbcbasedllapi.hxx> +#include <memory> + +namespace connectivity +{ + namespace odbc + { + /* + ** java_sql_ResultSet + */ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate> ODatabaseMetaDataResultSet_BASE; + + class OOO_DLLPUBLIC_ODBCBASE ODatabaseMetaDataResultSet : + public cppu::BaseMutex, + public ODatabaseMetaDataResultSet_BASE, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<ODatabaseMetaDataResultSet> + { + std::vector< sal_Int32> m_aColMapping; // pos 0 is unused so we don't have to decrement 1 every time + + std::map<sal_Int32, ::std::map<sal_Int32,sal_Int32> > + m_aValueRange; + + std::map<sal_Int32,SWORD> m_aODBCColumnTypes; + + SQLHANDLE m_aStatementHandle; // ... until freed + css::uno::WeakReferenceHelper m_aStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData> + m_xMetaData; + std::unique_ptr<SQLUSMALLINT[]> m_pRowStatusArray; + rtl::Reference<OConnection> m_pConnection; + rtl_TextEncoding m_nTextEncoding; + sal_Int32 m_nRowPos; + sal_Int32 m_nDriverColumnCount; // column count of the driver which can sometimes be less than the metadata count + SQLRETURN m_nCurrentFetchState; + bool m_bWasNull; + bool m_bEOF; // after last record + + // set the columncount of the driver + void checkColumnCount(); + static sal_Int32 getFetchDirection() { return css::sdbc::FetchDirection::FORWARD; } + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static sal_Int32 getFetchSize(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static OUString getCursorName(); + SWORD impl_getColumnType_nothrow(sal_Int32 columnIndex); + + sal_Int32 mapColumn (sal_Int32 column); + + protected: + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override; + virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override; + virtual ~ODatabaseMetaDataResultSet() override; + template < typename T, SQLSMALLINT sqlTypeId > T getInteger ( sal_Int32 columnIndex ); + + public: + // A ctor needed for returning the object + ODatabaseMetaDataResultSet(OConnection* _pConnection); + + + oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const + { + return m_pConnection->getOdbcFunction(_nIndex); + } + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + css::uno::Reference< css::uno::XInterface > operator *() + { + return css::uno::Reference< css::uno::XInterface >(*static_cast<ODatabaseMetaDataResultSet_BASE*>(this)); + } + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openTablesTypes( ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openTypeInfo(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openCatalogs(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openSchemas(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openTables(const css::uno::Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, const css::uno::Sequence< OUString >& types ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openColumnPrivileges( const css::uno::Any& catalog, const OUString& schema, + const OUString& table, const OUString& columnNamePattern ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openColumns( const css::uno::Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, const OUString& columnNamePattern ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openProcedureColumns( const css::uno::Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern,const OUString& columnNamePattern ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openProcedures( const css::uno::Any& catalog, const OUString& schemaPattern, + const OUString& procedureNamePattern); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openVersionColumns(const css::uno::Any& catalog, const OUString& schema, + const OUString& table); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openBestRowIdentifier( const css::uno::Any& catalog, const OUString& schema, + const OUString& table,sal_Int32 scope, bool nullable ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openForeignKeys( const css::uno::Any& catalog, const OUString* schema,const OUString* table, + const css::uno::Any& catalog2, const OUString* schema2,const OUString* table2); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openExportedKeys(const css::uno::Any& catalog, const OUString& schema,const OUString& table); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openImportedKeys(const css::uno::Any& catalog, const OUString& schema,const OUString& table); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openPrimaryKeys(const css::uno::Any& catalog, const OUString& schema,const OUString& table); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openTablePrivileges(const css::uno::Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openSpecialColumns(bool _bRowVer,const css::uno::Any& catalog, const OUString& schema, + const OUString& table,sal_Int32 scope, bool nullable ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void openIndexInfo( const css::uno::Any& catalog, const OUString& schema, + const OUString& table,bool unique,bool approximate ); + + protected: + using OPropertySetHelper::getFastPropertyValue; + }; + } + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODATABASEMETADATARESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/ODriver.hxx b/connectivity/source/inc/odbc/ODriver.hxx new file mode 100644 index 000000000..6172cd01a --- /dev/null +++ b/connectivity/source/inc/odbc/ODriver.hxx @@ -0,0 +1,87 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODRIVER_HXX + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <cppuhelper/compbase.hxx> +#include <connectivity/odbc.hxx> +#include <odbc/odbcbasedllapi.hxx> +#include <connectivity/CommonTools.hxx> +#include <osl/module.h> +#include <odbc/OTools.hxx> + +namespace connectivity +{ + namespace odbc + { + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XDriver, css::lang::XServiceInfo > ODriver_BASE; + + class OOO_DLLPUBLIC_ODBCBASE SAL_NO_VTABLE ODBCDriver : public ODriver_BASE + { + protected: + ::osl::Mutex m_aMutex; + + connectivity::OWeakRefArray m_xConnections; // vector containing a list + // of all the Connection objects + // for this Driver + + css::uno::Reference< css::lang::XMultiServiceFactory > m_xORB; + SQLHANDLE m_pDriverHandle; + + virtual SQLHANDLE EnvironmentHandle(OUString &_rPath) = 0; + + public: + + ODBCDriver(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxFactory); + + // only possibility to get the odbc functions + virtual oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const = 0; + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XDriver + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connect( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Bool SAL_CALL acceptsURL( const OUString& url ) override; + virtual css::uno::Sequence< css::sdbc::DriverPropertyInfo > SAL_CALL getPropertyInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual sal_Int32 SAL_CALL getMajorVersion( ) override; + virtual sal_Int32 SAL_CALL getMinorVersion( ) override; + + const css::uno::Reference< css::lang::XMultiServiceFactory >& getORB() const { return m_xORB; } + }; + } + +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODRIVER_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/OFunctions.hxx b/connectivity/source/inc/odbc/OFunctions.hxx new file mode 100644 index 000000000..95787a1db --- /dev/null +++ b/connectivity/source/inc/odbc/OFunctions.hxx @@ -0,0 +1,603 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OFUNCTIONS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OFUNCTIONS_HXX + +#include <connectivity/odbc.hxx> +#include <rtl/ustring.hxx> +#include <osl/module.h> + +namespace connectivity +{ + +// sal_Bool LoadFunctions(oslModule pODBCso, sal_Bool _bDS=sal_True); +bool LoadLibrary_ODBC3(OUString &_rPath); +// sal_Bool LoadLibrary_ADABAS(OUString &_rPath); + + // Connecting to a data source + typedef SQLRETURN (SQL_API *T3SQLAllocHandle) (SQLSMALLINT HandleType,SQLHANDLE InputHandle,SQLHANDLE * OutputHandlePtr); + + #define N3SQLAllocHandle(a,b,c) (*reinterpret_cast<T3SQLAllocHandle>(getOdbcFunction(ODBC3SQLFunctionId::AllocHandle)))(a,b,c) + + typedef SQLRETURN (SQL_API *T3SQLConnect) (SQLHDBC ConnectionHandle,SQLCHAR *ServerName,SQLSMALLINT NameLength1,SQLCHAR *UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3); + + #define N3SQLConnect(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLConnect>(getOdbcFunction(ODBC3SQLFunctionId::Connect)))(a,b,c,d,e,f,g) + + typedef SQLRETURN (SQL_API *T3SQLDriverConnect) ( SQLHDBC ConnectionHandle, + HWND WindowHandle, + SQLCHAR * InConnectionString, + SQLSMALLINT StringLength1, + SQLCHAR * OutConnectionString, + SQLSMALLINT BufferLength, + SQLSMALLINT * StringLength2Ptr, + SQLUSMALLINT DriverCompletion); + + #define N3SQLDriverConnect(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDriverConnect>(getOdbcFunction(ODBC3SQLFunctionId::DriverConnect)))(a,b,c,d,e,f,g,h) + + typedef SQLRETURN (SQL_API *T3SQLBrowseConnect) ( SQLHDBC ConnectionHandle, + SQLCHAR * InConnectionString, + SQLSMALLINT StringLength1, + SQLCHAR * OutConnectionString, + SQLSMALLINT BufferLength, + SQLSMALLINT * StringLength2Ptr); + + #define N3SQLBrowseConnect(a,b,c,d,e,f) (*reinterpret_cast<T3SQLBrowseConnect>(getOdbcFunction(ODBC3SQLFunctionId::BrowseConnect)))(a,b,c,d,e,f) + + // Obtaining information about a driver and data source + typedef SQLRETURN (SQL_API *T3SQLDataSources) ( SQLHENV EnvironmentHandle, + SQLUSMALLINT Direction, + SQLCHAR * ServerName, + SQLSMALLINT BufferLength1, + SQLSMALLINT * NameLength1Ptr, + SQLCHAR * Description, + SQLSMALLINT BufferLength2, + SQLSMALLINT * NameLength2Ptr); + + #define N3SQLDataSources(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDataSources>(getOdbcFunction(ODBC3SQLFunctionId::DataSources)))(a,b,c,d,e,f,g,h) + + typedef SQLRETURN (SQL_API *T3SQLDrivers) ( SQLHENV EnvironmentHandle, + SQLUSMALLINT Direction, + SQLCHAR * DriverDescription, + SQLSMALLINT BufferLength1, + SQLSMALLINT * DescriptionLengthPtr, + SQLCHAR * DriverAttributes, + SQLSMALLINT BufferLength2, + SQLSMALLINT * AttributesLengthPtr); + + #define N3SQLDrivers(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLDrivers>(getOdbcFunction(ODBC3SQLFunctionId::Drivers)))(a,b,c,d,e,f,g,h) + + typedef SQLRETURN (SQL_API *T3SQLGetInfo) ( SQLHDBC ConnectionHandle, + SQLUSMALLINT InfoType, + SQLPOINTER InfoValuePtr, + SQLSMALLINT BufferLength, + SQLSMALLINT * StringLengthPtr); + + #define N3SQLGetInfo(a,b,c,d,e) (*reinterpret_cast<T3SQLGetInfo>(getOdbcFunction(ODBC3SQLFunctionId::GetInfo)))(a,b,c,d,e) + + typedef SQLRETURN (SQL_API *T3SQLGetFunctions) (SQLHDBC ConnectionHandle, + SQLUSMALLINT FunctionId, + SQLUSMALLINT * SupportedPtr); + + #define N3SQLGetFunctions(a,b,c) (*reinterpret_cast<T3SQLGetFunctions>(getOdbcFunction(ODBC3SQLFunctionId::GetFunctions)))(a,b,c) + + typedef SQLRETURN (SQL_API *T3SQLGetTypeInfo) ( SQLHSTMT StatementHandle, + SQLSMALLINT DataType); + + #define N3SQLGetTypeInfo(a,b) (*reinterpret_cast<T3SQLGetTypeInfo>(getOdbcFunction(ODBC3SQLFunctionId::GetTypeInfo)))(a,b) + + // Setting and retrieving driver attributes + typedef SQLRETURN (SQL_API *T3SQLSetConnectAttr)(SQLHDBC ConnectionHandle, + SQLINTEGER Attribute, + SQLPOINTER ValuePtr, + SQLINTEGER StringLength); + + #define N3SQLSetConnectAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetConnectAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetConnectAttr)))(a,b,c,d) + + typedef SQLRETURN (SQL_API *T3SQLGetConnectAttr) (SQLHDBC ConnectionHandle, + SQLINTEGER Attribute, + SQLPOINTER ValuePtr, + SQLINTEGER BufferLength, + SQLINTEGER* StringLength); + + #define N3SQLGetConnectAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetConnectAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetConnectAttr)))(a,b,c,d,e) + + + typedef SQLRETURN (SQL_API *T3SQLSetEnvAttr) ( SQLHENV EnvironmentHandle, + SQLINTEGER Attribute, + SQLPOINTER ValuePtr, + SQLINTEGER StringLength); + + #define N3SQLSetEnvAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetEnvAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetEnvAttr)))(a,b,c,d) + + typedef SQLRETURN (SQL_API *T3SQLGetEnvAttr) ( SQLHENV EnvironmentHandle, + SQLINTEGER Attribute, + SQLPOINTER ValuePtr, + SQLINTEGER BufferLength, + SQLINTEGER* StringLength); + + #define N3SQLGetEnvAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetEnvAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetEnvAttr)))(a,b,c,d,e) + + + typedef SQLRETURN (SQL_API *T3SQLSetStmtAttr) ( SQLHSTMT StatementHandle, + SQLINTEGER Attribute, + SQLPOINTER ValuePtr, + SQLINTEGER StringLength); + + #define N3SQLSetStmtAttr(a,b,c,d) (*reinterpret_cast<T3SQLSetStmtAttr>(getOdbcFunction(ODBC3SQLFunctionId::SetStmtAttr)))(a,b,c,d) + + typedef SQLRETURN (SQL_API *T3SQLGetStmtAttr) ( SQLHSTMT StatementHandle, + SQLINTEGER Attribute, + SQLPOINTER ValuePtr, + SQLINTEGER BufferLength, + SQLINTEGER* StringLength); + + #define N3SQLGetStmtAttr(a,b,c,d,e) (*reinterpret_cast<T3SQLGetStmtAttr>(getOdbcFunction(ODBC3SQLFunctionId::GetStmtAttr)))(a,b,c,d,e) + + // Setting and retrieving descriptor fields + /*typedef SQLRETURN (SQL_API *T3SQLSetDescField) (SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, + SQLSMALLINT FieldIdentifier, + SQLPOINTER ValuePtr, + SQLINTEGER BufferLength); + + #define N3SQLSetDescField(a,b,c,d,e) (*reinterpret_cast<T3SQLSetDescField>(getOdbcFunction(ODBC3SQLFunctionId::SetDescField)))(a,b,c,d,e) + + typedef SQLRETURN (SQL_API *T3SQLGetDescField) ( SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, + SQLSMALLINT FieldIdentifier, + SQLPOINTER ValuePtr, + SQLINTEGER BufferLength, + SQLINTEGER * StringLengthPtr); + + #define N3SQLGetDescField(a,b,c,d,e,f) (*reinterpret_cast<T3SQLGetDescField>(getOdbcFunction(ODBC3SQLFunctionId::GetDescField)))(a,b,c,d,e,f) + + + typedef SQLRETURN (SQL_API *T3SQLGetDescRec) ( SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, + SQLCHAR * Name, + SQLSMALLINT BufferLength, + SQLSMALLINT * StringLengthPtr, + SQLSMALLINT * TypePtr, + SQLSMALLINT * SubTypePtr, + SQLLEN * LengthPtr, + SQLSMALLINT * PrecisionPtr, + SQLSMALLINT * ScalePtr, + SQLSMALLINT * NullablePtr); + + #define N3SQLGetDescRec(a,b,c,d,e,f,g,h,i,j,k) (*reinterpret_cast<T3SQLGetDescRec>(getOdbcFunction(ODBC3SQLFunctionId::GetDescRec)))(a,b,c,d,e,f,g,h,i,j,k) + + + typedef SQLRETURN (SQL_API *T3SQLSetDescRec) ( SQLHDESC DescriptorHandle, + SQLSMALLINT RecNumber, + SQLSMALLINT Type, + SQLSMALLINT SubType, + SQLLEN Length, + SQLSMALLINT Precision, + SQLSMALLINT Scale, + SQLPOINTER DataPtr, + SQLLEN * StringLengthPtr, + SQLLEN * IndicatorPtr); + + #define N3SQLSetDescRec(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLSetDescRec>(getOdbcFunction(ODBC3SQLFunctionId::SetDescRec)))(a,b,c,d,e,f,g,h,i,j) + */ + + // Preparing SQL requests + typedef SQLRETURN (SQL_API *T3SQLPrepare) ( SQLHSTMT StatementHandle, + SQLCHAR * StatementText, + SQLINTEGER TextLength); + + #define N3SQLPrepare(a,b,c) (*reinterpret_cast<T3SQLPrepare>(getOdbcFunction(ODBC3SQLFunctionId::Prepare)))(a,b,c) + + typedef SQLRETURN (SQL_API *T3SQLBindParameter) (SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT InputOutputType, + SQLSMALLINT ValueType, + SQLSMALLINT ParameterType, + SQLULEN ColumnSize, + SQLSMALLINT DecimalDigits, + SQLPOINTER ParameterValuePtr, + SQLLEN BufferLength, + SQLLEN * StrLen_or_IndPtr); + + #define N3SQLBindParameter(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLBindParameter>(getOdbcFunction(ODBC3SQLFunctionId::BindParameter)))(a,b,c,d,e,f,g,h,i,j) + + /*typedef SQLRETURN (SQL_API *T3SQLGetCursorName) (SQLHSTMT StatementHandle, + SQLCHAR * CursorName, + SQLSMALLINT BufferLength, + SQLSMALLINT * NameLengthPtr); + + #define N3SQLGetCursorName(a,b,c,d) (*reinterpret_cast<T3SQLGetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::GetCursorName)))(a,b,c,d) + */ + + typedef SQLRETURN (SQL_API *T3SQLSetCursorName) (SQLHSTMT StatementHandle, + SQLCHAR * CursorName, + SQLSMALLINT NameLength); + + #define N3SQLSetCursorName(a,b,c) (*reinterpret_cast<T3SQLSetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::SetCursorName)))(a,b,c) + + // Submitting requests + typedef SQLRETURN (SQL_API *T3SQLExecute) ( SQLHSTMT StatementHandle); + + #define N3SQLExecute(a) (*reinterpret_cast<T3SQLExecute>(getOdbcFunction(ODBC3SQLFunctionId::Execute)))(a) + + typedef SQLRETURN (SQL_API *T3SQLExecDirect) ( SQLHSTMT StatementHandle, + SQLCHAR * StatementText, + SQLINTEGER TextLength); + + #define N3SQLExecDirect(a,b,c) (*reinterpret_cast<T3SQLExecDirect>(getOdbcFunction(ODBC3SQLFunctionId::ExecDirect)))(a,b,c) + + typedef SQLRETURN (SQL_API *T3SQLDescribeParam) (SQLHSTMT StatementHandle, + SQLUSMALLINT ParameterNumber, + SQLSMALLINT * DataTypePtr, + SQLULEN * ParameterSizePtr, + SQLSMALLINT * DecimalDigitsPtr, + SQLSMALLINT * NullablePtr); + + #define N3SQLDescribeParam(a,b,c,d,e,f) (*reinterpret_cast<T3SQLDescribeParam>(getOdbcFunction(ODBC3SQLFunctionId::DescribeParam)))(a,b,c,d,e,f) + + typedef SQLRETURN (SQL_API *T3SQLNumParams) ( SQLHSTMT StatementHandle, + SQLSMALLINT * ParameterCountPtr); + + #define N3SQLNumParams(a,b) (*reinterpret_cast<T3SQLNumParams>(getOdbcFunction(ODBC3SQLFunctionId::NumParams)))(a,b) + + typedef SQLRETURN (SQL_API *T3SQLParamData) ( SQLHSTMT StatementHandle, + SQLPOINTER * ValuePtrPtr); + + #define N3SQLParamData(a,b) (*reinterpret_cast<T3SQLParamData>(getOdbcFunction(ODBC3SQLFunctionId::ParamData)))(a,b) + + typedef SQLRETURN (SQL_API *T3SQLPutData) ( SQLHSTMT StatementHandle, + SQLPOINTER DataPtr, + SQLLEN StrLen_or_Ind); + + #define N3SQLPutData(a,b,c) (*reinterpret_cast<T3SQLPutData>(getOdbcFunction(ODBC3SQLFunctionId::PutData)))(a,b,c) + + // Retrieving results and information about results + typedef SQLRETURN (SQL_API *T3SQLRowCount) ( SQLHSTMT StatementHandle, + SQLLEN * RowCountPtr); + + #define N3SQLRowCount(a,b) (*reinterpret_cast<T3SQLRowCount>(getOdbcFunction(ODBC3SQLFunctionId::RowCount)))(a,b) + + typedef SQLRETURN (SQL_API *T3SQLNumResultCols) (SQLHSTMT StatementHandle, + SQLSMALLINT * ColumnCountPtr); + + #define N3SQLNumResultCols(a,b) (*reinterpret_cast<T3SQLNumResultCols>(getOdbcFunction(ODBC3SQLFunctionId::NumResultCols)))(a,b) + + typedef SQLRETURN (SQL_API *T3SQLDescribeCol) ( SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, + SQLCHAR * ColumnName, + SQLSMALLINT BufferLength, + SQLSMALLINT * NameLengthPtr, + SQLSMALLINT * DataTypePtr, + SQLULEN * ColumnSizePtr, + SQLSMALLINT * DecimalDigitsPtr, + SQLSMALLINT * NullablePtr); + + #define N3SQLDescribeCol(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLDescribeCol>(getOdbcFunction(ODBC3SQLFunctionId::DescribeCol)))(a,b,c,d,e,f,g,h,i) + + typedef SQLRETURN (SQL_API *T3SQLColAttribute) (SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, + SQLUSMALLINT FieldIdentifier, + SQLPOINTER CharacterAttributePtr, + SQLSMALLINT BufferLength, + SQLSMALLINT * StringLengthPtr, + SQLLEN * NumericAttributePtr); + + #define N3SQLColAttribute(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLColAttribute>(getOdbcFunction(ODBC3SQLFunctionId::ColAttribute)))(a,b,c,d,e,f,g) + + typedef SQLRETURN (SQL_API *T3SQLBindCol) ( SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, + SQLSMALLINT TargetType, + SQLPOINTER TargetValuePtr, + SQLLEN BufferLength, + SQLLEN * StrLen_or_IndPtr); + + #define N3SQLBindCol(a,b,c,d,e,f) (*reinterpret_cast<T3SQLBindCol>(getOdbcFunction(ODBC3SQLFunctionId::BindCol)))(a,b,c,d,e,f) + + typedef SQLRETURN (SQL_API *T3SQLFetch) ( SQLHSTMT StatementHandle); + + #define N3SQLFetch(a) (*reinterpret_cast<T3SQLFetch>(getOdbcFunction(ODBC3SQLFunctionId::Fetch)))(a) + + typedef SQLRETURN (SQL_API *T3SQLFetchScroll) ( SQLHSTMT StatementHandle, + SQLSMALLINT FetchOrientation, + SQLLEN FetchOffset); + + #define N3SQLFetchScroll(a,b,c) (*reinterpret_cast<T3SQLFetchScroll>(getOdbcFunction(ODBC3SQLFunctionId::FetchScroll)))(a,b,c) + + typedef SQLRETURN (SQL_API *T3SQLGetData) ( SQLHSTMT StatementHandle, + SQLUSMALLINT ColumnNumber, + SQLSMALLINT TargetType, + SQLPOINTER TargetValuePtr, + SQLLEN BufferLength, + SQLLEN * StrLen_or_IndPtr); + + #define N3SQLGetData(a,b,c,d,e,f) (*reinterpret_cast<T3SQLGetData>(getOdbcFunction(ODBC3SQLFunctionId::GetData)))(a,b,c,d,e,f) + + typedef SQLRETURN (SQL_API *T3SQLSetPos) ( SQLHSTMT StatementHandle, + SQLSETPOSIROW RowNumber, + SQLUSMALLINT Operation, + SQLUSMALLINT LockType); + + #define N3SQLSetPos(a,b,c,d) (*reinterpret_cast<T3SQLSetPos>(getOdbcFunction(ODBC3SQLFunctionId::SetPos)))(a,b,c,d) + + typedef SQLRETURN (SQL_API *T3SQLBulkOperations) ( SQLHSTMT StatementHandle, + SQLSMALLINT Operation); + + #define N3SQLBulkOperations(a,b) (*reinterpret_cast<T3SQLBulkOperations>(getOdbcFunction(ODBC3SQLFunctionId::BulkOperations)))(a,b) + + typedef SQLRETURN (SQL_API *T3SQLMoreResults) ( SQLHSTMT StatementHandle); + + #define N3SQLMoreResults(a) (*reinterpret_cast<T3SQLMoreResults>(getOdbcFunction(ODBC3SQLFunctionId::MoreResults)))(a) + + /*typedef SQLRETURN (SQL_API *T3SQLGetDiagField) (SQLSMALLINT HandleType, + SQLHANDLE Handle, + SQLSMALLINT RecNumber, + SQLSMALLINT DiagIdentifier, + SQLPOINTER DiagInfoPtr, + SQLSMALLINT BufferLength, + SQLSMALLINT * StringLengthPtr); + + #define N3SQLGetDiagField(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLGetDiagField>(getOdbcFunction(ODBC3SQLFunctionId::GetDiagField)))(a,b,c,d,e,f,g)*/ + + typedef SQLRETURN (SQL_API *T3SQLGetDiagRec) ( SQLSMALLINT HandleType, + SQLHANDLE Handle, + SQLSMALLINT RecNumber, + SQLCHAR * Sqlstate, + SQLINTEGER * NativeErrorPtr, + SQLCHAR * MessageText, + SQLSMALLINT BufferLength, + SQLSMALLINT * TextLengthPtr); + + + #define N3SQLGetDiagRec(a,b,c,d,e,f,g,h) (*reinterpret_cast<T3SQLGetDiagRec>(getOdbcFunction(ODBC3SQLFunctionId::GetDiagRec)))(a,b,c,d,e,f,g,h) + + // Obtaining information about the data source's system tables (catalog functions) + typedef SQLRETURN (SQL_API *T3SQLColumnPrivileges) (SQLHSTMT StatementHandle, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * TableName, + SQLSMALLINT NameLength3, + SQLCHAR * ColumnName, + SQLSMALLINT NameLength4); + + #define N3SQLColumnPrivileges(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLColumnPrivileges>(getOdbcFunction(ODBC3SQLFunctionId::ColumnPrivileges)))(a,b,c,d,e,f,g,h,i) + + typedef SQLRETURN (SQL_API *T3SQLColumns) ( SQLHSTMT StatementHandle, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * TableName, + SQLSMALLINT NameLength3, + SQLCHAR * ColumnName, + SQLSMALLINT NameLength4); + + #define N3SQLColumns(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLColumns>(getOdbcFunction(ODBC3SQLFunctionId::Columns)))(a,b,c,d,e,f,g,h,i) + + typedef SQLRETURN (SQL_API *T3SQLForeignKeys) ( SQLHSTMT StatementHandle, + SQLCHAR * PKCatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * PKSchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * PKTableName, + SQLSMALLINT NameLength3, + SQLCHAR * FKCatalogName, + SQLSMALLINT NameLength4, + SQLCHAR * FKSchemaName, + SQLSMALLINT NameLength5, + SQLCHAR * FKTableName, + SQLSMALLINT NameLength6); + + #define N3SQLForeignKeys(a,b,c,d,e,f,g,h,i,j,k,l,m) (*reinterpret_cast<T3SQLForeignKeys>(getOdbcFunction(ODBC3SQLFunctionId::ForeignKeys)))(a,b,c,d,e,f,g,h,i,j,k,l,m) + + typedef SQLRETURN (SQL_API *T3SQLPrimaryKeys) ( SQLHSTMT StatementHandle, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * TableName, + SQLSMALLINT NameLength3); + + #define N3SQLPrimaryKeys(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLPrimaryKeys>(getOdbcFunction(ODBC3SQLFunctionId::PrimaryKeys)))(a,b,c,d,e,f,g) + + typedef SQLRETURN (SQL_API *T3SQLProcedureColumns) (SQLHSTMT StatementHandle, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * ProcName, + SQLSMALLINT NameLength3, + SQLCHAR * ColumnName, + SQLSMALLINT NameLength4); + + #define N3SQLProcedureColumns(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLProcedureColumns>(getOdbcFunction(ODBC3SQLFunctionId::ProcedureColumns)))(a,b,c,d,e,f,g,h,i) + + typedef SQLRETURN (SQL_API *T3SQLProcedures) ( SQLHSTMT StatementHandle, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * ProcName, + SQLSMALLINT NameLength3); + + #define N3SQLProcedures(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLProcedures>(getOdbcFunction(ODBC3SQLFunctionId::Procedures)))(a,b,c,d,e,f,g) + + typedef SQLRETURN (SQL_API *T3SQLSpecialColumns) (SQLHSTMT StatementHandle, + SQLUSMALLINT IdentifierType, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * TableName, + SQLSMALLINT NameLength3, + SQLUSMALLINT Scope, + SQLUSMALLINT Nullable); + + #define N3SQLSpecialColumns(a,b,c,d,e,f,g,h,i,j) (*reinterpret_cast<T3SQLSpecialColumns>(getOdbcFunction(ODBC3SQLFunctionId::SpecialColumns)))(a,b,c,d,e,f,g,h,i,j) + + typedef SQLRETURN (SQL_API *T3SQLStatistics) ( SQLHSTMT StatementHandle, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * TableName, + SQLSMALLINT NameLength3, + SQLUSMALLINT Unique, + SQLUSMALLINT Reserved); + + #define N3SQLStatistics(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLStatistics>(getOdbcFunction(ODBC3SQLFunctionId::Statistics)))(a,b,c,d,e,f,g,h,i) + + typedef SQLRETURN (SQL_API *T3SQLTablePrivileges) (SQLHSTMT StatementHandle, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * TableName, + SQLSMALLINT NameLength3); + + #define N3SQLTablePrivileges(a,b,c,d,e,f,g) (*reinterpret_cast<T3SQLTablePrivileges>(getOdbcFunction(ODBC3SQLFunctionId::TablePrivileges)))(a,b,c,d,e,f,g) + + typedef SQLRETURN (SQL_API *T3SQLTables) ( SQLHSTMT StatementHandle, + SQLCHAR * CatalogName, + SQLSMALLINT NameLength1, + SQLCHAR * SchemaName, + SQLSMALLINT NameLength2, + SQLCHAR * TableName, + SQLSMALLINT NameLength3, + SQLCHAR * TableType, + SQLSMALLINT NameLength4); + + #define N3SQLTables(a,b,c,d,e,f,g,h,i) (*reinterpret_cast<T3SQLTables>(getOdbcFunction(ODBC3SQLFunctionId::Tables)))(a,b,c,d,e,f,g,h,i) + + // Terminating a statement + typedef SQLRETURN (SQL_API *T3SQLFreeStmt) ( SQLHSTMT StatementHandle, + SQLUSMALLINT Option); + + #define N3SQLFreeStmt(a,b) (*reinterpret_cast<T3SQLFreeStmt>(getOdbcFunction(ODBC3SQLFunctionId::FreeStmt)))(a,b) + + typedef SQLRETURN (SQL_API *T3SQLCloseCursor) (SQLHSTMT StatementHandle); + + #define N3SQLCloseCursor(a) (*reinterpret_cast<T3SQLCloseCursor>(getOdbcFunction(ODBC3SQLFunctionId::CloseCursor)))(a) + + typedef SQLRETURN (SQL_API *T3SQLCancel) ( SQLHSTMT StatementHandle); + + #define N3SQLCancel(a) (*reinterpret_cast<T3SQLCancel>(getOdbcFunction(ODBC3SQLFunctionId::Cancel)))(a) + + typedef SQLRETURN (SQL_API *T3SQLEndTran) ( SQLSMALLINT HandleType, + SQLHANDLE Handle, + SQLSMALLINT CompletionType); + + #define N3SQLEndTran(a,b,c) (*reinterpret_cast<T3SQLEndTran>(getOdbcFunction(ODBC3SQLFunctionId::EndTran)))(a,b,c) + + // Terminating a connection + typedef SQLRETURN (SQL_API *T3SQLDisconnect) (SQLHDBC ConnectionHandle); + + #define N3SQLDisconnect(a) (*reinterpret_cast<T3SQLDisconnect>(getOdbcFunction(ODBC3SQLFunctionId::Disconnect)))(a) + + typedef SQLRETURN (SQL_API *T3SQLFreeHandle) (SQLSMALLINT HandleType, + SQLHANDLE Handle); + + #define N3SQLFreeHandle(a,b) (*reinterpret_cast<T3SQLFreeHandle>(getOdbcFunction(ODBC3SQLFunctionId::FreeHandle)))(a,b) + + typedef SQLRETURN (SQL_API *T3SQLGetCursorName) ( SQLHSTMT StatementHandle, + SQLCHAR * CursorName, + SQLSMALLINT BufferLength, + SQLSMALLINT* NameLength2); + + #define N3SQLGetCursorName(a,b,c,d) (*reinterpret_cast<T3SQLGetCursorName>(getOdbcFunction(ODBC3SQLFunctionId::GetCursorName)))(a,b,c,d) + + typedef SQLRETURN (SQL_API *T3SQLNativeSql) ( SQLHSTMT ConnectionHandle, + SQLCHAR * InStatementText, + SQLINTEGER TextLength1, + SQLCHAR * OutStatementText, + SQLINTEGER BufferLength, + SQLINTEGER * TextLength2Ptr); + + #define N3SQLNativeSql(a,b,c,d,e,f) (*reinterpret_cast<T3SQLNativeSql>(getOdbcFunction(ODBC3SQLFunctionId::NativeSql)))(a,b,c,d,e,f) + + // extern declaration of the function pointer + extern T3SQLAllocHandle pODBC3SQLAllocHandle; + extern T3SQLConnect pODBC3SQLConnect; + extern T3SQLDriverConnect pODBC3SQLDriverConnect; + extern T3SQLBrowseConnect pODBC3SQLBrowseConnect; + extern T3SQLDataSources pODBC3SQLDataSources; + extern T3SQLDrivers pODBC3SQLDrivers; + extern T3SQLGetInfo pODBC3SQLGetInfo; + extern T3SQLGetFunctions pODBC3SQLGetFunctions; + extern T3SQLGetTypeInfo pODBC3SQLGetTypeInfo; + extern T3SQLSetConnectAttr pODBC3SQLSetConnectAttr; + extern T3SQLGetConnectAttr pODBC3SQLGetConnectAttr; + extern T3SQLSetEnvAttr pODBC3SQLSetEnvAttr; + extern T3SQLGetEnvAttr pODBC3SQLGetEnvAttr; + extern T3SQLSetStmtAttr pODBC3SQLSetStmtAttr; + extern T3SQLGetStmtAttr pODBC3SQLGetStmtAttr; + //extern T3SQLSetDescField pODBC3SQLSetDescField; + //extern T3SQLGetDescField pODBC3SQLGetDescField; + //extern T3SQLGetDescRec pODBC3SQLGetDescRec; + //extern T3SQLSetDescRec pODBC3SQLSetDescRec; + extern T3SQLPrepare pODBC3SQLPrepare; + extern T3SQLBindParameter pODBC3SQLBindParameter; + //extern T3SQLGetCursorName pODBC3SQLGetCursorName; + extern T3SQLSetCursorName pODBC3SQLSetCursorName; + extern T3SQLExecute pODBC3SQLExecute; + extern T3SQLExecDirect pODBC3SQLExecDirect; + //extern T3SQLNativeSql pODBC3SQLNativeSql; + extern T3SQLDescribeParam pODBC3SQLDescribeParam; + extern T3SQLNumParams pODBC3SQLNumParams; + extern T3SQLParamData pODBC3SQLParamData; + extern T3SQLPutData pODBC3SQLPutData; + extern T3SQLRowCount pODBC3SQLRowCount; + extern T3SQLNumResultCols pODBC3SQLNumResultCols; + extern T3SQLDescribeCol pODBC3SQLDescribeCol; + extern T3SQLColAttribute pODBC3SQLColAttribute; + extern T3SQLBindCol pODBC3SQLBindCol; + extern T3SQLFetch pODBC3SQLFetch; + extern T3SQLFetchScroll pODBC3SQLFetchScroll; + extern T3SQLGetData pODBC3SQLGetData; + extern T3SQLSetPos pODBC3SQLSetPos; + extern T3SQLBulkOperations pODBC3SQLBulkOperations; + extern T3SQLMoreResults pODBC3SQLMoreResults; + //extern T3SQLGetDiagField pODBC3SQLGetDiagField; + extern T3SQLGetDiagRec pODBC3SQLGetDiagRec; + extern T3SQLColumnPrivileges pODBC3SQLColumnPrivileges; + extern T3SQLColumns pODBC3SQLColumns; + extern T3SQLForeignKeys pODBC3SQLForeignKeys; + extern T3SQLPrimaryKeys pODBC3SQLPrimaryKeys; + extern T3SQLProcedureColumns pODBC3SQLProcedureColumns; + extern T3SQLProcedures pODBC3SQLProcedures; + extern T3SQLSpecialColumns pODBC3SQLSpecialColumns; + extern T3SQLStatistics pODBC3SQLStatistics; + extern T3SQLTablePrivileges pODBC3SQLTablePrivileges; + extern T3SQLTables pODBC3SQLTables; + extern T3SQLFreeStmt pODBC3SQLFreeStmt; + extern T3SQLCloseCursor pODBC3SQLCloseCursor; + extern T3SQLCancel pODBC3SQLCancel; + extern T3SQLEndTran pODBC3SQLEndTran; + extern T3SQLDisconnect pODBC3SQLDisconnect; + extern T3SQLFreeHandle pODBC3SQLFreeHandle; + extern T3SQLGetCursorName pODBC3SQLGetCursorName; + extern T3SQLNativeSql pODBC3SQLNativeSql; +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OFUNCTIONS_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/OPreparedStatement.hxx b/connectivity/source/inc/odbc/OPreparedStatement.hxx new file mode 100644 index 000000000..c593a859d --- /dev/null +++ b/connectivity/source/inc/odbc/OPreparedStatement.hxx @@ -0,0 +1,153 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OPREPAREDSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OPREPAREDSTATEMENT_HXX + +#include <odbc/odbcbasedllapi.hxx> +#include <odbc/OStatement.hxx> +#include <com/sun/star/sdbc/XPreparedStatement.hpp> +#include <com/sun/star/sdbc/XParameters.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <cppuhelper/implbase5.hxx> + +namespace connectivity +{ + namespace odbc + { + + class OBoundParam; + typedef ::cppu::ImplHelper5< css::sdbc::XPreparedStatement, + css::sdbc::XParameters, + css::sdbc::XPreparedBatchExecution, + css::sdbc::XResultSetMetaDataSupplier, + css::lang::XServiceInfo> OPreparedStatement_BASE; + + class OOO_DLLPUBLIC_ODBCBASE OPreparedStatement final : + public OStatement_BASE2, + public OPreparedStatement_BASE + { + static const short invalid_scale = -1; + + // Data attributes + + SQLSMALLINT numParams; // Number of parameter markers for the prepared statement + + std::unique_ptr<OBoundParam[]> boundParams; + // Array of bound parameter objects. Each parameter marker will have a + // corresponding object to hold bind information, and resulting data. + css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData; + bool m_bPrepared; + + void FreeParams(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void putParamData (sal_Int32 index); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setStream (sal_Int32 ParameterIndex,const css::uno::Reference< css::io::XInputStream>& x, + SQLLEN length,sal_Int32 SQLtype); + SQLLEN* getLengthBuf (sal_Int32 index); + void* allocBindBuf ( sal_Int32 index, sal_Int32 bufLen); + /// @throws css::sdbc::SQLException + void initBoundParam (); + void setParameterPre(sal_Int32 parameterIndex); + template <typename T> void setScalarParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, const T i_Value); + template <typename T> void setScalarParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, sal_Int32 _nScale, const T i_Value); + void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, sal_Int32 _nScale, const void* _pData, SQLULEN _nDataLen, SQLLEN _nDataAllocLen); + // Wrappers for special cases + void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, sal_Int16 _nScale, const OUString &_sData); + void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, const css::uno::Sequence< sal_Int8 > &Data); + + bool isPrepared() const { return m_bPrepared;} + void prepareStatement(); + void checkParameterIndex(sal_Int32 _parameterIndex); + + /** + creates the driver specific resultset (factory) + */ + virtual OResultSet* createResulSet() override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, + const css::uno::Any& rValue) override; + public: + DECLARE_SERVICE_INFO(); + // A ctor, needed to return the object + OPreparedStatement( OConnection* _pConnection,const OUString& sql); + virtual ~OPreparedStatement() override; + OPreparedStatement& operator=( OPreparedStatement const & ) = delete; // MSVC2015 workaround + OPreparedStatement( OPreparedStatement const & ) = delete; // MSVC2015 workaround + + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPreparedStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override; + virtual sal_Int32 SAL_CALL executeUpdate( ) override; + virtual sal_Bool SAL_CALL execute( ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override; + // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + // XPreparedBatchExecution + virtual void SAL_CALL addBatch( ) override; + virtual void SAL_CALL clearBatch( ) override; + virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + + public: + using OStatement_Base::executeQuery; + using OStatement_Base::executeUpdate; + using OStatement_Base::execute; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OPREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/OResultSet.hxx b/connectivity/source/inc/odbc/OResultSet.hxx new file mode 100644 index 000000000..960db1824 --- /dev/null +++ b/connectivity/source/inc/odbc/OResultSet.hxx @@ -0,0 +1,358 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ORESULTSET_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ORESULTSET_HXX + +#include <com/sun/star/sdbc/FetchDirection.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/XColumnLocate.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbcx/XRowLocate.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <cppuhelper/compbase.hxx> +#include <comphelper/proparrhlp.hxx> +#include <odbc/OFunctions.hxx> +#include <odbc/OStatement.hxx> +#include <odbc/odbcbasedllapi.hxx> +#include <connectivity/CommonTools.hxx> +#include <connectivity/FValue.hxx> +#include <TSkipDeletedSet.hxx> +#include <memory> + +namespace connectivity +{ + namespace odbc + { + + /* + ** java_sql_ResultSet + */ + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XResultSet, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::util::XCancellable, + css::sdbc::XWarningsSupplier, + css::sdbc::XResultSetUpdate, + css::sdbc::XRowUpdate, + css::sdbcx::XRowLocate, + css::sdbcx::XDeleteRows, + css::sdbc::XCloseable, + css::sdbc::XColumnLocate, + css::lang::XServiceInfo> OResultSet_BASE; + + + typedef std::pair<sal_Int64,sal_Int32> TVoidPtr; + typedef std::allocator< TVoidPtr > TVoidAlloc; + typedef std::vector<TVoidPtr> TVoidVector; + /// Functor object for class ZZ returntype is void + struct OOO_DLLPUBLIC_ODBCBASE TBookmarkPosMapCompare + { + bool operator()( const css::uno::Sequence<sal_Int8>& _rLH, + const css::uno::Sequence<sal_Int8>& _rRH) const + { + if(_rLH.getLength() == _rRH.getLength()) + { + sal_Int32 nCount = _rLH.getLength(); + if(nCount != 4) + { + const sal_Int8* pLHBack = _rLH.getConstArray() + nCount - 1; + const sal_Int8* pRHBack = _rRH.getConstArray() + nCount - 1; + + sal_Int32 i; + for(i=0;i < nCount;++i,--pLHBack,--pRHBack) + { + if(!(*pLHBack) && *pRHBack) + return true; + else if(*pLHBack && !(*pRHBack)) + return false; + } + for(i=0,++pLHBack,++pRHBack;i < nCount;++pLHBack,++pRHBack,++i) + if(*pLHBack < *pRHBack) + return true; + return false; + } + else + return *reinterpret_cast<const sal_Int32*>(_rLH.getConstArray()) < *reinterpret_cast<const sal_Int32*>(_rRH.getConstArray()); + + } + else + return _rLH.getLength() < _rRH.getLength(); + } + }; + + typedef std::map< css::uno::Sequence<sal_Int8>, sal_Int32,TBookmarkPosMapCompare > TBookmarkPosMap; + + class OOO_DLLPUBLIC_ODBCBASE OResultSet : + public cppu::BaseMutex, + public ::connectivity::IResultSetHelper, + public OResultSet_BASE, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<OResultSet> + { + protected: + TBookmarkPosMap m_aPosToBookmarks; + // used top hold the information about the value and the datatype to save calls to metadata + typedef std::vector<ORowSetValue> TDataRow; + + TVoidVector m_aBindVector; + std::vector<SQLLEN> m_aLengthVector; + std::map<sal_Int32,SWORD> m_aODBCColumnTypes; + + // In baseline ODBC, SQLGetData can only be called on monotonically increasing column numbers. + // additionally, any variable-length data can be fetched only once (possibly in parts); + // after that, SQLGetData returns SQL_NO_DATA. + // In order to insulate our callers from these restrictions, + // we cache the current row in m_aRow. + // If the driver claims to support the GD_ANY_ORDER extension, + // we read and cache only the columns requested by a caller. + // Else, we read and cache all columns whose number is <= a requested column. + // m_aRow[colNumber].getBound() says if it contains an up-to-date value or not. + TDataRow m_aRow; + bool m_bFetchDataInOrder; + SQLHANDLE m_aStatementHandle; + SQLHANDLE m_aConnectionHandle; + OStatement_Base* m_pStatement; + std::unique_ptr<OSkipDeletedSet> m_pSkipDeletedSet; + css::uno::Reference< css::uno::XInterface> m_xStatement; + css::uno::Reference< css::sdbc::XResultSetMetaData> m_xMetaData; + std::unique_ptr<SQLUSMALLINT[]> m_pRowStatusArray; + rtl_TextEncoding m_nTextEncoding; + sal_Int32 m_nRowPos; + mutable sal_uInt32 m_nUseBookmarks; + SQLRETURN m_nCurrentFetchState; + bool m_bWasNull; + bool m_bEOF; // after last record + bool m_bRowInserted; + bool m_bRowDeleted; + bool m_bUseFetchScroll; + + bool isBookmarkable() const; + sal_Int32 getResultSetConcurrency() const; + sal_Int32 getResultSetType() const; + static sal_Int32 getFetchDirection() { return css::sdbc::FetchDirection::FORWARD; } + sal_Int32 getFetchSize() const; + OUString getCursorName() const; + template < typename T, SQLINTEGER BufferLength > T getStmtOption (SQLINTEGER fOption) const; + + void setFetchDirection(sal_Int32 _par0); + void setFetchSize(sal_Int32 _par0); + template < typename T, SQLINTEGER BufferLength > SQLRETURN setStmtOption (SQLINTEGER fOption, T value) const; + + + void ensureCacheForColumn(sal_Int32 columnIndex); + void invalidateCache(); + void fillColumn(sal_Int32 _nToColumn); + void allocBuffer(); + void releaseBuffer(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void updateValue(sal_Int32 columnIndex, SQLSMALLINT _nType, void const * _pValue); + void fillNeededData(SQLRETURN _nRet); + bool moveImpl(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset); + TVoidPtr allocBindColumn(sal_Int32 _nType,sal_Int32 _nColumnIndex); + SQLRETURN unbind(bool _bUnbindHandle = true); + SWORD impl_getColumnType_nothrow(sal_Int32 columnIndex); + + // helper to implement XRow::getXXX in simple cases + template < typename T > T getValue( sal_Int32 columnIndex ); + // impl_getXXX are the functions that do the actual fetching from ODBC, ignoring the cache + // for simple cases + template < typename T > T impl_getValue( const sal_Int32 _nColumnIndex, SQLSMALLINT nType ); + // these cases need some special treatment + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + bool impl_getBoolean( sal_Int32 columnIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Sequence< sal_Int8 > impl_getBytes( sal_Int32 columnIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::util::Date impl_getDate( sal_Int32 columnIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::util::Time impl_getTime( sal_Int32 columnIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::util::DateTime impl_getTimestamp( sal_Int32 columnIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int64 impl_getLong( sal_Int32 columnIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OUString impl_getString( sal_Int32 columnIndex ); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Sequence<sal_Int8> impl_getBookmark( ); + + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + public: + DECLARE_SERVICE_INFO(); + // A ctor that is needed for returning the object + OResultSet( SQLHANDLE _pStatementHandle,OStatement_Base* pStmt); + virtual ~OResultSet() override; + + void construct(); + + oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const + { + return m_pStatement->getOdbcFunction(_nIndex); + } + + css::uno::Reference< css::uno::XInterface > operator *() + { + return css::uno::Reference< css::uno::XInterface >(*static_cast<OResultSet_BASE*>(this)); + } + + void setMetaData(const css::uno::Reference< css::sdbc::XResultSetMetaData>& _xMetaData) { m_xMetaData = _xMetaData;} + + // ::cppu::OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XResultSet + virtual sal_Bool SAL_CALL next( ) override; + virtual sal_Bool SAL_CALL isBeforeFirst( ) override; + virtual sal_Bool SAL_CALL isAfterLast( ) override; + virtual sal_Bool SAL_CALL isFirst( ) override; + virtual sal_Bool SAL_CALL isLast( ) override; + virtual void SAL_CALL beforeFirst( ) override; + virtual void SAL_CALL afterLast( ) override; + virtual sal_Bool SAL_CALL first( ) override; + virtual sal_Bool SAL_CALL last( ) override; + virtual sal_Int32 SAL_CALL getRow( ) override; + virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override; + virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override; + virtual sal_Bool SAL_CALL previous( ) override; + virtual void SAL_CALL refreshRow( ) override; + virtual sal_Bool SAL_CALL rowUpdated( ) override; + virtual sal_Bool SAL_CALL rowInserted( ) override; + virtual sal_Bool SAL_CALL rowDeleted( ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override; + // XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + // XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + // XColumnLocate + virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override; + // XRowLocate + virtual css::uno::Any SAL_CALL getBookmark( ) override; + virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override; + virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override; + virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override; + virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override; + virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override; + // XDeleteRows + virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override; + + // IResultSetHelper + virtual bool move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData) override; + virtual sal_Int32 getDriverPos() const override; + virtual bool isRowDeleted() const override; + + protected: + using OPropertySetHelper::getFastPropertyValue; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ORESULTSET_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/OResultSetMetaData.hxx b/connectivity/source/inc/odbc/OResultSetMetaData.hxx new file mode 100644 index 000000000..b1ffb20ce --- /dev/null +++ b/connectivity/source/inc/odbc/OResultSetMetaData.hxx @@ -0,0 +1,120 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ORESULTSETMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ORESULTSETMETADATA_HXX + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include <odbc/OFunctions.hxx> +#include <odbc/odbcbasedllapi.hxx> +#include <vector> +#include <odbc/OConnection.hxx> + +namespace connectivity +{ + namespace odbc + { + + //************ Class: ResultSetMetaData + + typedef ::cppu::WeakImplHelper< css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE; + + class OOO_DLLPUBLIC_ODBCBASE OResultSetMetaData final : + public OResultSetMetaData_BASE + { + std::vector<sal_Int32> m_vMapping; // when not every column is needed + std::map<sal_Int32,sal_Int32> m_aColumnTypes; + + SQLHANDLE m_aStatementHandle; + OConnection* m_pConnection; + sal_Int32 m_nColCount; + bool m_bUseODBC2Types; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + OUString getCharColAttrib(sal_Int32 column,sal_Int32 ident); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getNumColAttrib(sal_Int32 column,sal_Int32 ident); + public: + // A ctor that is needed for returning the object + OResultSetMetaData(OConnection* _pConnection, SQLHANDLE _pStmt ) + :m_aStatementHandle( _pStmt ) + ,m_pConnection(_pConnection) + ,m_nColCount(-1) + ,m_bUseODBC2Types(false) + {} + OResultSetMetaData(OConnection* _pConnection, SQLHANDLE _pStmt ,const std::vector<sal_Int32> & _vMapping) + :m_vMapping(_vMapping) + ,m_aStatementHandle( _pStmt ) + ,m_pConnection(_pConnection) + ,m_nColCount(_vMapping.size()-1) + ,m_bUseODBC2Types(false) + {} + virtual ~OResultSetMetaData() override; + + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static SQLLEN getNumColAttrib(OConnection const * _pConnection + ,SQLHANDLE _aStatementHandle + ,const css::uno::Reference< css::uno::XInterface >& _xInterface + ,sal_Int32 _column + ,sal_Int32 ident); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static SQLSMALLINT getColumnODBCType(OConnection const * _pConnection + ,SQLHANDLE _aStatementHandle + ,const css::uno::Reference< css::uno::XInterface >& _xInterface + ,sal_Int32 column); + + oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const + { + return m_pConnection->getOdbcFunction(_nIndex); + } + + virtual sal_Int32 SAL_CALL getColumnCount( ) override; + virtual sal_Bool SAL_CALL isAutoIncrement( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCaseSensitive( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSearchable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isCurrency( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL isNullable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isSigned( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnDisplaySize( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnLabel( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnName( sal_Int32 column ) override; + virtual OUString SAL_CALL getSchemaName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getPrecision( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getScale( sal_Int32 column ) override; + virtual OUString SAL_CALL getTableName( sal_Int32 column ) override; + virtual OUString SAL_CALL getCatalogName( sal_Int32 column ) override; + virtual sal_Int32 SAL_CALL getColumnType( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnTypeName( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isReadOnly( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isWritable( sal_Int32 column ) override; + virtual sal_Bool SAL_CALL isDefinitelyWritable( sal_Int32 column ) override; + virtual OUString SAL_CALL getColumnServiceName( sal_Int32 column ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ORESULTSETMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/OStatement.hxx b/connectivity/source/inc/odbc/OStatement.hxx new file mode 100644 index 000000000..5beaf9bb6 --- /dev/null +++ b/connectivity/source/inc/odbc/OStatement.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OSTATEMENT_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OSTATEMENT_HXX + +#include <com/sun/star/sdbc/XStatement.hpp> +#include <com/sun/star/sdbc/XWarningsSupplier.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> +#include <com/sun/star/sdbc/XBatchExecution.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/sdbc/SQLWarning.hpp> +#include <com/sun/star/sdbc/XGeneratedResultSet.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <comphelper/proparrhlp.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <connectivity/CommonTools.hxx> +#include <odbc/OFunctions.hxx> +#include <odbc/OConnection.hxx> +#include <odbc/odbcbasedllapi.hxx> +#include <vector> +#include <com/sun/star/lang/XServiceInfo.hpp> + +namespace connectivity +{ + namespace odbc + { + + typedef ::cppu::WeakComponentImplHelper< css::sdbc::XStatement, + css::sdbc::XWarningsSupplier, + css::util::XCancellable, + css::sdbc::XCloseable, + css::sdbc::XGeneratedResultSet, + css::sdbc::XMultipleResults> OStatement_BASE; + + class OResultSet; + + //************ Class: java.sql.Statement + + class OOO_DLLPUBLIC_ODBCBASE OStatement_Base : + public cppu::BaseMutex, + public OStatement_BASE, + public ::cppu::OPropertySetHelper, + public ::comphelper::OPropertyArrayUsageHelper<OStatement_Base> + + { + css::sdbc::SQLWarning m_aLastWarning; + protected: + css::uno::WeakReference< css::sdbc::XResultSet> m_xResultSet; // The last ResultSet created + css::uno::Reference< css::sdbc::XStatement> m_xGeneratedStatement; + // for this Statement + + std::vector< OUString> m_aBatchVector; + OUString m_sSqlStatement; + + rtl::Reference<OConnection> m_pConnection;// The owning Connection object + SQLHANDLE m_aStatementHandle; + SQLUSMALLINT* m_pRowStatusArray; + + protected: + + sal_Int64 getQueryTimeOut() const; + sal_Int64 getMaxFieldSize() const; + sal_Int64 getMaxRows() const; + sal_Int32 getResultSetConcurrency() const; + sal_Int32 getResultSetType() const; + sal_Int32 getFetchDirection() const; + sal_Int32 getFetchSize() const; + OUString getCursorName() const; + bool isUsingBookmarks() const; + bool getEscapeProcessing() const; + template < typename T, SQLINTEGER BufferLength > T getStmtOption (SQLINTEGER fOption) const; + + void setQueryTimeOut(sal_Int64 _par0) ; + void setMaxFieldSize(sal_Int64 _par0) ; + void setMaxRows(sal_Int64 _par0) ; + void setFetchDirection(sal_Int32 _par0) ; + void setFetchSize(sal_Int32 _par0) ; + void setCursorName(const OUString &_par0); + void setEscapeProcessing( const bool _bEscapeProc ); + template < typename T, SQLINTEGER BufferLength > SQLRETURN setStmtOption (SQLINTEGER fOption, T value) const; + + void setResultSetConcurrency(sal_Int32 _par0) ; + void setResultSetType(sal_Int32 _par0) ; + void setUsingBookmarks(bool _bUseBookmark) ; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void reset(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void clearMyResultSet(); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void setWarning (const css::sdbc::SQLWarning &ex); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + bool lockIfNecessary (const OUString& sql); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + sal_Int32 getColumnCount(); + + + // getResultSet + // getResultSet returns the current result as a ResultSet. It + // returns NULL if the current result is not a ResultSet. + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + css::uno::Reference<css::sdbc::XResultSet> getResultSet(bool checkCount); + /** + creates the driver specific resultset (factory) + */ + virtual OResultSet* createResulSet(); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + SQLLEN getRowCount(); + + + void disposeResultSet(); + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + virtual ~OStatement_Base() override; + + public: + OStatement_Base(OConnection* _pConnection ); + using OStatement_BASE::operator css::uno::Reference< css::uno::XInterface >; + + oslGenericFunction getOdbcFunction(ODBC3SQLFunctionId _nIndex) const + { + return m_pConnection->getOdbcFunction(_nIndex); + } + // OComponentHelper + virtual void SAL_CALL disposing() override; + // XInterface + virtual void SAL_CALL release() throw() override; + virtual void SAL_CALL acquire() throw() override; + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + // XStatement + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override ; + virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override ; + virtual sal_Bool SAL_CALL execute( const OUString& sql ) override ; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override ; + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + // XCancellable + virtual void SAL_CALL cancel( ) override; + // XCloseable + virtual void SAL_CALL close( ) override; + // XMultipleResults + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override; + virtual sal_Int32 SAL_CALL getUpdateCount( ) override; + virtual sal_Bool SAL_CALL getMoreResults( ) override; + //XGeneratedResultSet + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues( ) override; + + // other methods + SQLHANDLE getConnectionHandle() { return m_pConnection->getConnection(); } + OConnection* getOwnConnection() const { return m_pConnection.get();} + /** getCursorProperties return the properties for a specific cursor type + @param _nCursorType the CursorType + @param bFirst when true the first property set is returned + + @return the cursor properties + */ + SQLUINTEGER getCursorProperties(SQLINTEGER _nCursorType, bool bFirst); + + protected: + using OPropertySetHelper::getFastPropertyValue; + }; + + class OOO_DLLPUBLIC_ODBCBASE OStatement_BASE2 : public OStatement_Base + { + public: + OStatement_BASE2(OConnection* _pConnection ) : + OStatement_Base(_pConnection ) + {} + // OComponentHelper + virtual void SAL_CALL disposing() override; + }; + + class OOO_DLLPUBLIC_ODBCBASE OStatement : + public OStatement_BASE2, + public css::sdbc::XBatchExecution, + public css::lang::XServiceInfo + { + protected: + virtual ~OStatement() override {} + public: + // A ctor that is needed for returning the object + OStatement( OConnection* _pConnection) : OStatement_BASE2( _pConnection){} + DECLARE_SERVICE_INFO(); + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + // XBatchExecution + virtual void SAL_CALL addBatch( const OUString& sql ) override; + virtual void SAL_CALL clearBatch( ) override; + virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override; + }; + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/OTools.hxx b/connectivity/source/inc/odbc/OTools.hxx new file mode 100644 index 000000000..3f2fddb81 --- /dev/null +++ b/connectivity/source/inc/odbc/OTools.hxx @@ -0,0 +1,250 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OTOOLS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OTOOLS_HXX + +#include <connectivity/odbc.hxx> +#include <odbc/odbcbasedllapi.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 <osl/thread.h> +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <rtl/textenc.h> + +enum class ODBC3SQLFunctionId +{ + AllocHandle = 1, + Connect = 2, + DriverConnect = 3, + BrowseConnect = 4, + DataSources = 5, + Drivers = 6, + GetInfo = 7, + GetFunctions = 8, + GetTypeInfo = 9, + SetConnectAttr = 10, + GetConnectAttr = 11, + SetEnvAttr = 12, + GetEnvAttr = 13, + SetStmtAttr = 14, + GetStmtAttr = 15, + Prepare = 16, + BindParameter = 17, + SetCursorName = 18, + Execute = 19, + ExecDirect = 20, + DescribeParam = 21, + NumParams = 22, + ParamData = 23, + PutData = 24, + RowCount = 25, + NumResultCols = 26, + DescribeCol = 27, + ColAttribute = 28, + BindCol = 29, + Fetch = 30, + FetchScroll = 31, + GetData = 32, + SetPos = 33, + BulkOperations = 34, + MoreResults = 35, + GetDiagRec = 36, + ColumnPrivileges = 37, + Columns = 38, + ForeignKeys = 39, + PrimaryKeys = 40, + ProcedureColumns = 41, + Procedures = 42, + SpecialColumns = 43, + Statistics = 44, + TablePrivileges = 45, + Tables = 46, + FreeStmt = 47, + CloseCursor = 48, + Cancel = 49, + EndTran = 50, + Disconnect = 51, + FreeHandle = 52, + GetCursorName = 53, + NativeSql = 54, +}; + +namespace connectivity +{ + namespace odbc + { + class OConnection; + + const sal_Int32 MAX_PUT_DATA_LENGTH = 2000; + + class OOO_DLLPUBLIC_ODBCBASE OTools + { + public: + /// @throws css::sdbc::SQLException + static void ThrowException( const OConnection* _pConnection, + SQLRETURN _rRetCode, + SQLHANDLE _pContext, + SQLSMALLINT _nHandleType, + const css::uno::Reference< css::uno::XInterface >& _xInterface, + bool _bNoFound=true); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static void GetInfo(OConnection const * _pConnection, + SQLHANDLE _aConnectionHandle, + SQLUSMALLINT _nInfo, + OUString &_rValue, + const css::uno::Reference< css::uno::XInterface >& _xInterface, + rtl_TextEncoding _nTextEncoding); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static void GetInfo(OConnection const * _pConnection, + SQLHANDLE _aConnectionHandle, + SQLUSMALLINT _nInfo, + sal_Int32 &_rValue, + const css::uno::Reference< css::uno::XInterface >& _xInterface); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static void GetInfo(OConnection const * _pConnection, + SQLHANDLE _aConnectionHandle, + SQLUSMALLINT _nInfo, + SQLUSMALLINT &_rValue, + const css::uno::Reference< css::uno::XInterface >& _xInterface); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static void GetInfo(OConnection const * _pConnection, + SQLHANDLE _aConnectionHandle, + SQLUSMALLINT _nInfo, + SQLUINTEGER &_rValue, + const css::uno::Reference< css::uno::XInterface >& _xInterface); + + static sal_Int32 MapOdbcType2Jdbc(SQLSMALLINT _nType); + static SQLSMALLINT jdbcTypeToOdbc(sal_Int32 jdbcType); + + static DATE_STRUCT DateToOdbcDate(const css::util::Date& x) + { + DATE_STRUCT aVal; + aVal.year = x.Year; + aVal.month = x.Month; + aVal.day = x.Day; + return aVal; + } + static TIME_STRUCT TimeToOdbcTime(const css::util::Time& x) + { + TIME_STRUCT aVal; + aVal.hour = x.Hours; + aVal.minute = x.Minutes; + aVal.second = x.Seconds; + return aVal; + } + static TIMESTAMP_STRUCT DateTimeToTimestamp(const css::util::DateTime& x) + { + TIMESTAMP_STRUCT aVal; + aVal.year = x.Year; + aVal.month = x.Month; + aVal.day = x.Day; + aVal.hour = x.Hours; + aVal.minute = x.Minutes; + aVal.second = x.Seconds; + aVal.fraction = x.NanoSeconds; + return aVal; + } + /** + getBindTypes set the ODBC type for C + @param _bUseWChar true when Unicode should be used + @param _bUseOldTimeDate true when the old datetime format should be used + @param _nOdbcType the ODBC sql type + @param fCType the C type for the ODBC type + @param fSqlType the SQL type for the ODBC type + */ + static void getBindTypes(bool _bUseWChar, + bool _bUseOldTimeDate, + SQLSMALLINT _nOdbcType, + SQLSMALLINT& fCType, + SQLSMALLINT& fSqlType); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static OUString getStringValue( OConnection const * _pConnection, + SQLHANDLE _aStatementHandle, + sal_Int32 columnIndex, + SQLSMALLINT _fSqlType, + bool &_bWasNull, + const css::uno::Reference< css::uno::XInterface >& _xInterface, + rtl_TextEncoding _nTextEncoding); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static css::uno::Sequence<sal_Int8> getBytesValue(const OConnection* _pConnection, + SQLHANDLE _aStatementHandle, + sal_Int32 columnIndex, + SQLSMALLINT _fSqlType, + bool &_bWasNull, + const css::uno::Reference< css::uno::XInterface >& _xInterface); + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static void getValue( OConnection const * _pConnection, + SQLHANDLE _aStatementHandle, + sal_Int32 columnIndex, + SQLSMALLINT _nType, + bool &_bWasNull, + const css::uno::Reference< css::uno::XInterface >& _xInterface, + void* _pValue, + SQLLEN _nSize); + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + static void bindValue( OConnection const * _pConnection, + SQLHANDLE _aStatementHandle, + sal_Int32 columnIndex, + SQLSMALLINT _nType, + SQLSMALLINT _nMaxLen, + const void* _pValue, + void* _pData, + SQLLEN *pLen, + const css::uno::Reference< css::uno::XInterface >& _xInterface, + rtl_TextEncoding _nTextEncoding, + bool _bUseOldTimeDate); + }; + + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + template <class T> void getValue( const OConnection* _pConnection, + SQLHANDLE _aStatementHandle, + sal_Int32 columnIndex, + SQLSMALLINT _nType, + bool &_bWasNull, + const css::uno::Reference< css::uno::XInterface >& _xInterface, + T& _rValue) + { + OTools::getValue(_pConnection,_aStatementHandle,columnIndex,_nType,_bWasNull,_xInterface,&_rValue,sizeof _rValue); + } + + + } +} +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_OTOOLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/odbc/odbcbasedllapi.hxx b/connectivity/source/inc/odbc/odbcbasedllapi.hxx new file mode 100644 index 000000000..59619eee7 --- /dev/null +++ b/connectivity/source/inc/odbc/odbcbasedllapi.hxx @@ -0,0 +1,35 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODBCBASEDLLAPI_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_ODBC_ODBCBASEDLLAPI_HXX + +#include <sal/config.h> + +#include <sal/types.h> + +#if defined OOO_DLLIMPLEMENTATION_ODBCBASE +#define OOO_DLLPUBLIC_ODBCBASE SAL_DLLPUBLIC_EXPORT +#else +#define OOO_DLLPUBLIC_ODBCBASE SAL_DLLPUBLIC_IMPORT +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/propertyids.hxx b/connectivity/source/inc/propertyids.hxx new file mode 100644 index 000000000..538fe88c5 --- /dev/null +++ b/connectivity/source/inc/propertyids.hxx @@ -0,0 +1,112 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_PROPERTYIDS_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_PROPERTYIDS_HXX + +// this define has to be set to split the names into different dll's or so's +// every dll has his own set of property names +#include <rtl/ustring.hxx> +#include <map> +#include <connectivity/dbtoolsdllapi.hxx> + +namespace dbtools +{ + class OOO_DLLPUBLIC_DBTOOLS OPropertyMap + { + std::map<sal_Int32, OUString> m_aPropertyMap; + public: + OPropertyMap(); + const OUString& getNameByIndex(sal_Int32 _nIndex) const; + }; +} + +#define PROPERTY_ID_QUERYTIMEOUT 1 +#define PROPERTY_ID_MAXFIELDSIZE 2 +#define PROPERTY_ID_MAXROWS 3 +#define PROPERTY_ID_CURSORNAME 4 +#define PROPERTY_ID_RESULTSETCONCURRENCY 5 +#define PROPERTY_ID_RESULTSETTYPE 6 +#define PROPERTY_ID_FETCHDIRECTION 7 +#define PROPERTY_ID_FETCHSIZE 8 +#define PROPERTY_ID_ESCAPEPROCESSING 9 +#define PROPERTY_ID_USEBOOKMARKS 10 +// Column +#define PROPERTY_ID_NAME 11 +#define PROPERTY_ID_TYPE 12 +#define PROPERTY_ID_TYPENAME 13 +#define PROPERTY_ID_PRECISION 14 +#define PROPERTY_ID_SCALE 15 +#define PROPERTY_ID_ISNULLABLE 16 +#define PROPERTY_ID_ISAUTOINCREMENT 17 +#define PROPERTY_ID_ISROWVERSION 18 +#define PROPERTY_ID_DESCRIPTION 19 +#define PROPERTY_ID_DEFAULTVALUE 20 + +#define PROPERTY_ID_REFERENCEDTABLE 21 +#define PROPERTY_ID_UPDATERULE 22 +#define PROPERTY_ID_DELETERULE 23 +#define PROPERTY_ID_CATALOG 24 +#define PROPERTY_ID_ISUNIQUE 25 +#define PROPERTY_ID_ISPRIMARYKEYINDEX 26 +#define PROPERTY_ID_ISCLUSTERED 27 +#define PROPERTY_ID_ISASCENDING 28 +#define PROPERTY_ID_SCHEMANAME 29 +#define PROPERTY_ID_CATALOGNAME 30 + +#define PROPERTY_ID_COMMAND 31 +#define PROPERTY_ID_CHECKOPTION 32 +#define PROPERTY_ID_PASSWORD 33 +#define PROPERTY_ID_RELATEDCOLUMN 34 + +#define PROPERTY_ID_FUNCTION 35 +#define PROPERTY_ID_TABLENAME 36 +#define PROPERTY_ID_REALNAME 37 +#define PROPERTY_ID_DBASEPRECISIONCHANGED 38 +#define PROPERTY_ID_ISCURRENCY 39 +#define PROPERTY_ID_ISBOOKMARKABLE 40 + +#define PROPERTY_ID_INVALID_INDEX 41 +#define PROPERTY_ID_HY010 43 +#define PROPERTY_ID_LABEL 44 +#define PROPERTY_ID_DELIMITER 45 +#define PROPERTY_ID_FORMATKEY 46 +#define PROPERTY_ID_LOCALE 47 +#define PROPERTY_ID_IM001 48 + +#define PROPERTY_ID_AUTOINCREMENTCREATION 49 + +#define PROPERTY_ID_PRIVILEGES 50 +#define PROPERTY_ID_HAVINGCLAUSE 51 + +#define PROPERTY_ID_ISSIGNED 52 +#define PROPERTY_ID_AGGREGATEFUNCTION 53 +#define PROPERTY_ID_ISSEARCHABLE 54 + +#define PROPERTY_ID_APPLYFILTER 55 +#define PROPERTY_ID_FILTER 56 +#define PROPERTY_ID_MASTERFIELDS 57 +#define PROPERTY_ID_DETAILFIELDS 58 +#define PROPERTY_ID_FIELDTYPE 59 +#define PROPERTY_ID_VALUE 60 +#define PROPERTY_ID_ACTIVE_CONNECTION 61 + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_PROPERTYIDS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/resource/sharedresources.hxx b/connectivity/source/inc/resource/sharedresources.hxx new file mode 100644 index 000000000..bc4c1aeca --- /dev/null +++ b/connectivity/source/inc/resource/sharedresources.hxx @@ -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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_RESOURCE_SHAREDRESOURCES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_RESOURCE_SHAREDRESOURCES_HXX + +#include <rtl/ustring.hxx> +#include <vector> +#include <connectivity/dbtoolsdllapi.hxx> + + +namespace connectivity +{ + + + typedef sal_uInt16 ResourceId; + + /** helper class for accessing resources shared by different libraries + in the connectivity module + */ + class OOO_DLLPUBLIC_DBTOOLS SharedResources + { + public: + SharedResources(); + ~SharedResources(); + + /** loads a string from the shared resource file + @param pResId + the resource ID of the string + @return + the string from the resource file + */ + OUString + getResourceString( + const char* pResId + ) const; + + /** loads a string from the shared resource file, and replaces + a given ASCII pattern with a given string + + @param pResId + the resource ID of the string to load + @param _pAsciiPatternToReplace + the ASCII string which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute + the String which should substitute the ASCII pattern. + + @return + the string from the resource file, with applied string substitution + */ + OUString + getResourceStringWithSubstitution( + const char* pResId, + const char* _pAsciiPatternToReplace, + const OUString& _rStringToSubstitute + ) const; + + /** loads a string from the shared resource file, and replaces + a given ASCII pattern with a given string + + @param pResId + the resource ID of the string to load + @param _pAsciiPatternToReplace1 + the ASCII string (1) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute1 + the String which should substitute the ASCII pattern (1) + @param _pAsciiPatternToReplace2 + the ASCII string (2) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute2 + the String which should substitute the ASCII pattern (2) + + @return + the string from the resource file, with applied string substitution + */ + OUString + getResourceStringWithSubstitution( + const char* pResId, + const char* _pAsciiPatternToReplace1, + const OUString& _rStringToSubstitute1, + const char* _pAsciiPatternToReplace2, + const OUString& _rStringToSubstitute2 + ) const; + + /** loads a string from the shared resource file, and replaces + a given ASCII pattern with a given string + + @param pResId + the resource ID of the string to load + @param _pAsciiPatternToReplace1 + the ASCII string (1) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute1 + the String which should substitute the ASCII pattern (1) + @param _pAsciiPatternToReplace2 + the ASCII string (2) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute2 + the String which should substitute the ASCII pattern (2) + @param _pAsciiPatternToReplace3 + the ASCII string (3) which is to search in the string. Must not be <NULL/>. + @param _rStringToSubstitute3 + the String which should substitute the ASCII pattern (3) + + @return + the string from the resource file, with applied string substitution + */ + OUString + getResourceStringWithSubstitution( + const char* pResId, + const char* _pAsciiPatternToReplace1, + const OUString& _rStringToSubstitute1, + const char* _pAsciiPatternToReplace2, + const OUString& _rStringToSubstitute2, + const char* _pAsciiPatternToReplace3, + const OUString& _rStringToSubstitute3 + ) const; + + /** loads a string from the shared resource file, and replaces a given ASCII pattern with a given string + + @param pResId + the resource ID of the string to load + @param _aStringToSubstitutes + A list of substitutions. + + @return + the string from the resource file, with applied string substitution + */ + OUString getResourceStringWithSubstitution( const char* pResId, + const std::vector< std::pair<const char* , OUString > >& _rStringToSubstitutes) const; + }; + + +} // namespace connectivity + + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_RESOURCE_SHAREDRESOURCES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/writer/WCatalog.hxx b/connectivity/source/inc/writer/WCatalog.hxx new file mode 100644 index 000000000..a6d8bd93d --- /dev/null +++ b/connectivity/source/inc/writer/WCatalog.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WCATALOG_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WCATALOG_HXX + +#include <file/FCatalog.hxx> + +namespace connectivity +{ +namespace writer +{ +class OWriterConnection; +class OWriterCatalog : public file::OFileCatalog +{ +public: + void refreshTables() override; + + OWriterCatalog(OWriterConnection* pConnection); +}; + +} // namespace writer +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WCATALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/writer/WConnection.hxx b/connectivity/source/inc/writer/WConnection.hxx new file mode 100644 index 000000000..5b3eae535 --- /dev/null +++ b/connectivity/source/inc/writer/WConnection.hxx @@ -0,0 +1,169 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WCONNECTION_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WCONNECTION_HXX + +#include <memory> +#include <file/FConnection.hxx> +#include <com/sun/star/frame/XDesktop2.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <unotools/closeveto.hxx> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace text +{ +class XTextDocument; +} +} +} +} + +namespace utl +{ +class CloseVeto; +} + +namespace connectivity +{ +namespace writer +{ +class ODriver; +class OWriterConnection : public file::OConnection +{ + // the spreadsheet document: + css::uno::Reference<css::text::XTextDocument> m_xDoc; + OUString m_sPassword; + OUString m_aFileName; + oslInterlockedCount m_nDocCount; + + class CloseVetoButTerminateListener + : public cppu::WeakComponentImplHelper<css::frame::XTerminateListener> + { + private: + /// close listener that vetoes so nobody else disposes m_xDoc + std::unique_ptr<utl::CloseVeto> m_pCloseListener; + /// but also listen to XDesktop and if app is terminating anyway, dispose m_xDoc while + /// its still possible to do so properly + css::uno::Reference<css::frame::XDesktop2> m_xDesktop; + osl::Mutex m_aMutex; + + public: + CloseVetoButTerminateListener() + : cppu::WeakComponentImplHelper<css::frame::XTerminateListener>(m_aMutex) + { + } + + void start(const css::uno::Reference<css::uno::XInterface>& rCloseable, + const css::uno::Reference<css::frame::XDesktop2>& rDesktop) + { + m_xDesktop = rDesktop; + m_xDesktop->addTerminateListener(this); + m_pCloseListener = std::make_unique<utl::CloseVeto>(rCloseable, true); + } + + void stop() + { + m_pCloseListener.reset(); + if (!m_xDesktop.is()) + return; + m_xDesktop->removeTerminateListener(this); + m_xDesktop.clear(); + } + + // XTerminateListener + void SAL_CALL queryTermination(const css::lang::EventObject& /*rEvent*/) override {} + + void SAL_CALL notifyTermination(const css::lang::EventObject& /*rEvent*/) override + { + stop(); + } + + void SAL_CALL disposing() override + { + stop(); + cppu::WeakComponentImplHelperBase::disposing(); + } + + void SAL_CALL disposing(const css::lang::EventObject& rEvent) override + { + const bool bShutDown = (rEvent.Source == m_xDesktop); + if (bShutDown) + stop(); + } + }; + + rtl::Reference<CloseVetoButTerminateListener> m_xCloseVetoButTerminateListener; + +public: + OWriterConnection(ODriver* _pDriver); + ~OWriterConnection() override; + + void construct(const OUString& rURL, + const css::uno::Sequence<css::beans::PropertyValue>& rInfo) override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + + // OComponentHelper + void SAL_CALL disposing() override; + + // XConnection + css::uno::Reference<css::sdbc::XDatabaseMetaData> SAL_CALL getMetaData() override; + css::uno::Reference<css::sdbcx::XTablesSupplier> createCatalog() override; + css::uno::Reference<css::sdbc::XStatement> SAL_CALL createStatement() override; + css::uno::Reference<css::sdbc::XPreparedStatement> + SAL_CALL prepareStatement(const OUString& sql) override; + css::uno::Reference<css::sdbc::XPreparedStatement> + SAL_CALL prepareCall(const OUString& sql) override; + + // no interface methods + css::uno::Reference<css::text::XTextDocument> const& acquireDoc(); + void releaseDoc(); + + class ODocHolder + { + OWriterConnection* m_pConnection; + css::uno::Reference<css::text::XTextDocument> m_xDoc; + + public: + ODocHolder(OWriterConnection* _pConnection) + : m_pConnection(_pConnection) + { + m_xDoc = m_pConnection->acquireDoc(); + } + ~ODocHolder() + { + m_xDoc.clear(); + m_pConnection->releaseDoc(); + } + const css::uno::Reference<css::text::XTextDocument>& getDoc() const { return m_xDoc; } + }; +}; +} +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/writer/WDatabaseMetaData.hxx b/connectivity/source/inc/writer/WDatabaseMetaData.hxx new file mode 100644 index 000000000..b2d85cfa3 --- /dev/null +++ b/connectivity/source/inc/writer/WDatabaseMetaData.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WDATABASEMETADATA_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WDATABASEMETADATA_HXX + +#include <component/CDatabaseMetaData.hxx> + +namespace connectivity +{ +namespace writer +{ +class OWriterDatabaseMetaData : public component::OComponentDatabaseMetaData +{ + OUString SAL_CALL getURL() override; + css::uno::Reference<css::sdbc::XResultSet> + SAL_CALL getTables(const css::uno::Any& catalog, const OUString& schemaPattern, + const OUString& tableNamePattern, + const css::uno::Sequence<OUString>& types) override; + +protected: + ~OWriterDatabaseMetaData() override; + +public: + OWriterDatabaseMetaData(file::OConnection* pConnection); +}; + +} // namespace writer +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WDATABASEMETADATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/writer/WDriver.hxx b/connectivity/source/inc/writer/WDriver.hxx new file mode 100644 index 000000000..aa164df93 --- /dev/null +++ b/connectivity/source/inc/writer/WDriver.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WDRIVER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WDRIVER_HXX + +#include <file/FDriver.hxx> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace lang +{ +class XMultiServiceFactory; +} +} +} +} + +namespace connectivity +{ +namespace writer +{ +/// @throws css::uno::Exception +css::uno::Reference<css::uno::XInterface> +ODriver_CreateInstance(const css::uno::Reference<css::lang::XMultiServiceFactory>& _rxFactory); + +class ODriver : public file::OFileDriver +{ +public: + ODriver(const css::uno::Reference<css::uno::XComponentContext>& _rxContext) + : file::OFileDriver(_rxContext) + { + } + + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + OUString SAL_CALL getImplementationName() override; + + // XDriver + css::uno::Reference<css::sdbc::XConnection> + SAL_CALL connect(const OUString& url, + const css::uno::Sequence<css::beans::PropertyValue>& info) override; + sal_Bool SAL_CALL acceptsURL(const OUString& url) override; + css::uno::Sequence<css::sdbc::DriverPropertyInfo> SAL_CALL getPropertyInfo( + const OUString& url, const css::uno::Sequence<css::beans::PropertyValue>& info) override; +}; +} +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WDRIVER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/writer/WTable.hxx b/connectivity/source/inc/writer/WTable.hxx new file mode 100644 index 000000000..fa533e1e3 --- /dev/null +++ b/connectivity/source/inc/writer/WTable.hxx @@ -0,0 +1,91 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WTABLE_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WTABLE_HXX + +#include <component/CTable.hxx> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace text +{ +class XTextTable; +} +} +} +} + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace util +{ +class XNumberFormats; +} +} +} +} + +namespace connectivity +{ +namespace writer +{ +using OWriterTable_BASE = component::OComponentTable; +class OWriterConnection; + +class OWriterTable : public OWriterTable_BASE +{ +private: + css::uno::Reference<css::text::XTextTable> m_xTable; + OWriterConnection* m_pWriterConnection; + sal_Int32 m_nStartCol; + sal_Int32 m_nDataCols; + bool m_bHasHeaders; + + void fillColumns(); + +public: + OWriterTable(sdbcx::OCollection* _pTables, OWriterConnection* _pConnection, + const OUString& Name, const OUString& Type); + + bool fetchRow(OValueRefRow& _rRow, const OSQLColumns& _rCols, bool bRetrieveData) override; + + void SAL_CALL disposing() override; + + // css::lang::XUnoTunnel + sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8>& rId) override; + static css::uno::Sequence<sal_Int8> getUnoTunnelId(); + + void construct() override; +}; + +} // namespace writer +} // namespace connectivity + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/inc/writer/WTables.hxx b/connectivity/source/inc/writer/WTables.hxx new file mode 100644 index 000000000..5477d89e0 --- /dev/null +++ b/connectivity/source/inc/writer/WTables.hxx @@ -0,0 +1,49 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WTABLES_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WTABLES_HXX + +#include <file/FTables.hxx> + +namespace connectivity +{ +namespace writer +{ +using OWriterTables_BASE = file::OTables; + +class OWriterTables : public OWriterTables_BASE +{ +protected: + sdbcx::ObjectType createObject(const OUString& rName) override; + +public: + OWriterTables(const css::uno::Reference<css::sdbc::XDatabaseMetaData>& _rMetaData, + ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, + const ::std::vector<OUString>& _rVector) + : OWriterTables_BASE(_rMetaData, _rParent, _rMutex, _rVector) + { + } +}; +} +} + +#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_WRITER_WTABLES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/manager/mdrivermanager.cxx b/connectivity/source/manager/mdrivermanager.cxx new file mode 100644 index 000000000..275cbb51f --- /dev/null +++ b/connectivity/source/manager/mdrivermanager.cxx @@ -0,0 +1,681 @@ +/* -*- 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 "mdrivermanager.hxx" +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/logging/LogLevel.hpp> + +#include <tools/diagnose_ex.h> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/diagnose.h> + +#include <algorithm> +#include <iterator> +#include <vector> + +namespace drivermanager +{ + +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 ::com::sun::star::container; +using namespace ::com::sun::star::logging; +using namespace ::osl; + +#define SERVICE_SDBC_DRIVER "com.sun.star.sdbc.Driver" + +/// @throws NoSuchElementException +static void throwNoSuchElementException() +{ + throw NoSuchElementException(); +} + +class ODriverEnumeration : public ::cppu::WeakImplHelper< XEnumeration > +{ + friend class OSDBCDriverManager; + + typedef std::vector< Reference< XDriver > > DriverArray; + DriverArray m_aDrivers; + DriverArray::const_iterator m_aPos; + // order matters! + +protected: + virtual ~ODriverEnumeration() override; +public: + explicit ODriverEnumeration(const DriverArray& _rDriverSequence); + +// XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements( ) override; + virtual Any SAL_CALL nextElement( ) override; +}; + + +ODriverEnumeration::ODriverEnumeration(const DriverArray& _rDriverSequence) + :m_aDrivers( _rDriverSequence ) + ,m_aPos( m_aDrivers.begin() ) +{ +} + + +ODriverEnumeration::~ODriverEnumeration() +{ +} + + +sal_Bool SAL_CALL ODriverEnumeration::hasMoreElements( ) +{ + return m_aPos != m_aDrivers.end(); +} + + +Any SAL_CALL ODriverEnumeration::nextElement( ) +{ + if ( !hasMoreElements() ) + throwNoSuchElementException(); + + return makeAny( *m_aPos++ ); +} + + namespace { + + /// an STL functor which ensures that a SdbcDriver described by a DriverAccess is loaded + struct EnsureDriver + { + explicit EnsureDriver( const Reference< XComponentContext > &rxContext ) + : mxContext( rxContext ) {} + + const DriverAccess& operator()( const DriverAccess& _rDescriptor ) const + { + // we did not load this driver, yet + if (!_rDescriptor.xDriver.is()) + { + // we have a factory for it + if (_rDescriptor.xComponentFactory.is()) + { + DriverAccess& rDesc = const_cast<DriverAccess&>(_rDescriptor); + try + { + //load driver + rDesc.xDriver.set( + rDesc.xComponentFactory->createInstanceWithContext(mxContext), css::uno::UNO_QUERY); + } + catch (const Exception&) + { + //failure, abandon driver + rDesc.xComponentFactory.clear(); + } + } + } + return _rDescriptor; + } + + private: + Reference< XComponentContext > mxContext; + }; + + /// an STL functor which extracts a SdbcDriver from a DriverAccess + struct ExtractDriverFromAccess + { + const Reference<XDriver>& operator()( const DriverAccess& _rAccess ) const + { + return _rAccess.xDriver; + } + }; + + struct ExtractDriverFromCollectionElement + { + const Reference<XDriver>& operator()( const DriverCollection::value_type& _rElement ) const + { + return _rElement.second; + } + }; + + // predicate for checking whether or not a driver accepts a given URL + class AcceptsURL + { + protected: + const OUString& m_rURL; + + public: + // ctor + explicit AcceptsURL( const OUString& _rURL ) : m_rURL( _rURL ) { } + + + bool operator()( const Reference<XDriver>& _rDriver ) const + { + // ask the driver + return _rDriver.is() && _rDriver->acceptsURL( m_rURL ); + } + }; + + } + + static sal_Int32 lcl_getDriverPrecedence( const Reference<XComponentContext>& _rContext, Sequence< OUString >& _rPrecedence ) + { + _rPrecedence.realloc( 0 ); + try + { + // create a configuration provider + Reference< XMultiServiceFactory > xConfigurationProvider( + css::configuration::theDefaultProvider::get( _rContext ) ); + + // one argument for creating the node access: the path to the configuration node + Sequence< Any > aCreationArgs(1); + aCreationArgs[0] <<= NamedValue( "nodepath", makeAny( OUString("org.openoffice.Office.DataAccess/DriverManager") ) ); + + // create the node access + Reference< XNameAccess > xDriverManagerNode( + xConfigurationProvider->createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", aCreationArgs), + UNO_QUERY); + + OSL_ENSURE(xDriverManagerNode.is(), "lcl_getDriverPrecedence: could not open my configuration node!"); + if (xDriverManagerNode.is()) + { + // obtain the preference list + Any aPreferences = xDriverManagerNode->getByName("DriverPrecedence"); + bool bSuccess = aPreferences >>= _rPrecedence; + OSL_ENSURE(bSuccess || !aPreferences.hasValue(), "lcl_getDriverPrecedence: invalid value for the preferences node (no string sequence but not NULL)!"); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.manager"); + } + + return _rPrecedence.getLength(); + } + + namespace { + + /// an STL argorithm compatible predicate comparing two DriverAccess instances by their implementation names + struct CompareDriverAccessByName + { + + bool operator()( const DriverAccess& lhs, const DriverAccess& rhs ) + { + return lhs.sImplementationName < rhs.sImplementationName; + } + }; + + /// and STL argorithm compatible predicate comparing a DriverAccess' impl name to a string + struct EqualDriverAccessToName + { + OUString m_sImplName; + explicit EqualDriverAccessToName(const OUString& _sImplName) : m_sImplName(_sImplName){} + + bool operator()( const DriverAccess& lhs) + { + return lhs.sImplementationName == m_sImplName; + } + }; + + } + +OSDBCDriverManager::OSDBCDriverManager( const Reference< XComponentContext >& _rxContext ) + :m_xContext( _rxContext ) + ,m_aEventLogger( _rxContext, "org.openoffice.logging.sdbc.DriverManager" ) + ,m_aDriverConfig(m_xContext) + ,m_nLoginTimeout(0) +{ + // bootstrap all objects supporting the .sdb.Driver service + bootstrapDrivers(); + + // initialize the drivers order + initializeDriverPrecedence(); +} + + +OSDBCDriverManager::~OSDBCDriverManager() +{ +} + +void OSDBCDriverManager::bootstrapDrivers() +{ + Reference< XContentEnumerationAccess > xEnumAccess( m_xContext->getServiceManager(), UNO_QUERY ); + Reference< XEnumeration > xEnumDrivers; + if (xEnumAccess.is()) + xEnumDrivers = xEnumAccess->createContentEnumeration(SERVICE_SDBC_DRIVER); + + OSL_ENSURE( xEnumDrivers.is(), "OSDBCDriverManager::bootstrapDrivers: no enumeration for the drivers available!" ); + if (!xEnumDrivers.is()) + return; + + Reference< XSingleComponentFactory > xFactory; + Reference< XServiceInfo > xSI; + while (xEnumDrivers->hasMoreElements()) + { + xFactory.set(xEnumDrivers->nextElement(), css::uno::UNO_QUERY); + OSL_ENSURE( xFactory.is(), "OSDBCDriverManager::bootstrapDrivers: no factory extracted" ); + + if ( xFactory.is() ) + { + // we got a factory for the driver + DriverAccess aDriverDescriptor; + bool bValidDescriptor = false; + + // can it tell us something about the implementation name? + xSI.set(xFactory, css::uno::UNO_QUERY); + if ( xSI.is() ) + { // yes -> no need to load the driver immediately (load it later when needed) + aDriverDescriptor.sImplementationName = xSI->getImplementationName(); + aDriverDescriptor.xComponentFactory = xFactory; + bValidDescriptor = true; + + m_aEventLogger.log( LogLevel::CONFIG, + "found SDBC driver $1$, no need to load it", + aDriverDescriptor.sImplementationName + ); + } + else + { + // no -> create the driver + Reference< XDriver > xDriver( xFactory->createInstanceWithContext( m_xContext ), UNO_QUERY ); + OSL_ENSURE( xDriver.is(), "OSDBCDriverManager::bootstrapDrivers: a driver which is no driver?!" ); + + if ( xDriver.is() ) + { + aDriverDescriptor.xDriver = xDriver; + // and obtain it's implementation name + xSI.set(xDriver, css::uno::UNO_QUERY); + OSL_ENSURE( xSI.is(), "OSDBCDriverManager::bootstrapDrivers: a driver without service info?" ); + if ( xSI.is() ) + { + aDriverDescriptor.sImplementationName = xSI->getImplementationName(); + bValidDescriptor = true; + + m_aEventLogger.log( LogLevel::CONFIG, + "found SDBC driver $1$, needed to load it", + aDriverDescriptor.sImplementationName + ); + } + } + } + + if ( bValidDescriptor ) + { + m_aDriversBS.push_back( aDriverDescriptor ); + } + } + } +} + + +void OSDBCDriverManager::initializeDriverPrecedence() +{ + if ( m_aDriversBS.empty() ) + // nothing to do + return; + + try + { + // get the precedence of the drivers from the configuration + Sequence< OUString > aDriverOrder; + if ( 0 == lcl_getDriverPrecedence( m_xContext, aDriverOrder ) ) + // nothing to do + return; + + // aDriverOrder now is the list of driver implementation names in the order they should be used + + if ( m_aEventLogger.isLoggable( LogLevel::CONFIG ) ) + { + sal_Int32 nOrderedCount = aDriverOrder.getLength(); + for ( sal_Int32 i=0; i<nOrderedCount; ++i ) + m_aEventLogger.log( LogLevel::CONFIG, + "configuration's driver order: driver $1$ of $2$: $3$", + static_cast<sal_Int32>(i + 1), nOrderedCount, aDriverOrder[i] + ); + } + + // sort our bootstrapped drivers + std::sort( m_aDriversBS.begin(), m_aDriversBS.end(), CompareDriverAccessByName() ); + + // the first driver for which there is no preference + DriverAccessArray::iterator aNoPrefDriversStart = m_aDriversBS.begin(); + // at the moment this is the first of all drivers we know + + // loop through the names in the precedence order + for ( const OUString& rDriverOrder : std::as_const(aDriverOrder) ) + { + if (aNoPrefDriversStart == m_aDriversBS.end()) + break; + + DriverAccess driver_order; + driver_order.sImplementationName = rDriverOrder; + + // look for the impl name in the DriverAccess array + std::pair< DriverAccessArray::iterator, DriverAccessArray::iterator > aPos = + std::equal_range( aNoPrefDriversStart, m_aDriversBS.end(), driver_order, CompareDriverAccessByName() ); + + if ( aPos.first != aPos.second ) + { // we have a DriverAccess with this impl name + + OSL_ENSURE( std::distance( aPos.first, aPos.second ) == 1, + "OSDBCDriverManager::initializeDriverPrecedence: more than one driver with this impl name? How this?" ); + // move the DriverAccess pointed to by aPos.first to the position pointed to by aNoPrefDriversStart + + if ( aPos.first != aNoPrefDriversStart ) + { // if this does not hold, the DriverAccess already has the correct position + + // rotate the range [aNoPrefDriversStart, aPos.second) right 1 element + std::rotate( aNoPrefDriversStart, aPos.second - 1, aPos.second ); + } + + // next round we start searching and pos right + ++aNoPrefDriversStart; + } + } + } + catch (Exception&) + { + OSL_FAIL("OSDBCDriverManager::initializeDriverPrecedence: caught an exception while sorting the drivers!"); + } +} + + +Reference< XConnection > SAL_CALL OSDBCDriverManager::getConnection( const OUString& _rURL ) +{ + MutexGuard aGuard(m_aMutex); + + m_aEventLogger.log( LogLevel::INFO, + "connection requested for URL $1$", + _rURL + ); + + Reference< XConnection > xConnection; + Reference< XDriver > xDriver = implGetDriverForURL(_rURL); + if (xDriver.is()) + { + // TODO : handle the login timeout + xConnection = xDriver->connect(_rURL, Sequence< PropertyValue >()); + // may throw an exception + m_aEventLogger.log( LogLevel::INFO, + "connection retrieved for URL $1$", + _rURL + ); + } + + return xConnection; +} + + +Reference< XConnection > SAL_CALL OSDBCDriverManager::getConnectionWithInfo( const OUString& _rURL, const Sequence< PropertyValue >& _rInfo ) +{ + MutexGuard aGuard(m_aMutex); + + m_aEventLogger.log( LogLevel::INFO, + "connection with info requested for URL $1$", + _rURL + ); + + Reference< XConnection > xConnection; + Reference< XDriver > xDriver = implGetDriverForURL(_rURL); + if (xDriver.is()) + { + // TODO : handle the login timeout + xConnection = xDriver->connect(_rURL, _rInfo); + // may throw an exception + m_aEventLogger.log( LogLevel::INFO, + "connection with info retrieved for URL $1$", + _rURL + ); + } + + return xConnection; +} + + +void SAL_CALL OSDBCDriverManager::setLoginTimeout( sal_Int32 seconds ) +{ + MutexGuard aGuard(m_aMutex); + m_nLoginTimeout = seconds; +} + + +sal_Int32 SAL_CALL OSDBCDriverManager::getLoginTimeout( ) +{ + MutexGuard aGuard(m_aMutex); + return m_nLoginTimeout; +} + + +Reference< XEnumeration > SAL_CALL OSDBCDriverManager::createEnumeration( ) +{ + MutexGuard aGuard(m_aMutex); + + ODriverEnumeration::DriverArray aDrivers; + + // ensure that all our bootstrapped drivers are instantiated + std::for_each( m_aDriversBS.begin(), m_aDriversBS.end(), EnsureDriver( m_xContext ) ); + + // copy the bootstrapped drivers + std::transform( + m_aDriversBS.begin(), // "copy from" start + m_aDriversBS.end(), // "copy from" end + std::back_inserter( aDrivers ), // insert into + ExtractDriverFromAccess() // transformation to apply (extract a driver from a driver access) + ); + + // append the runtime drivers + std::transform( + m_aDriversRT.begin(), // "copy from" start + m_aDriversRT.end(), // "copy from" end + std::back_inserter( aDrivers ), // insert into + ExtractDriverFromCollectionElement() // transformation to apply (extract a driver from a driver access) + ); + + return new ODriverEnumeration( aDrivers ); +} + + +css::uno::Type SAL_CALL OSDBCDriverManager::getElementType( ) +{ + return cppu::UnoType<XDriver>::get(); +} + + +sal_Bool SAL_CALL OSDBCDriverManager::hasElements( ) +{ + MutexGuard aGuard(m_aMutex); + return !(m_aDriversBS.empty() && m_aDriversRT.empty()); +} + + +OUString SAL_CALL OSDBCDriverManager::getImplementationName( ) +{ + return getImplementationName_static(); +} + +sal_Bool SAL_CALL OSDBCDriverManager::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + + +Sequence< OUString > SAL_CALL OSDBCDriverManager::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_static(); +} + + +Reference< XInterface > OSDBCDriverManager::Create( const Reference< XMultiServiceFactory >& _rxFactory ) +{ + return *( new OSDBCDriverManager( comphelper::getComponentContext(_rxFactory) ) ); +} + + +OUString OSDBCDriverManager::getImplementationName_static( ) +{ + return "com.sun.star.comp.sdbc.OSDBCDriverManager"; +} + + +Sequence< OUString > OSDBCDriverManager::getSupportedServiceNames_static( ) +{ + Sequence< OUString > aSupported { getSingletonName_static() }; + return aSupported; +} + + +OUString OSDBCDriverManager::getSingletonName_static( ) +{ + return "com.sun.star.sdbc.DriverManager"; +} + + +Reference< XInterface > SAL_CALL OSDBCDriverManager::getRegisteredObject( const OUString& _rName ) +{ + MutexGuard aGuard(m_aMutex); + DriverCollection::const_iterator aSearch = m_aDriversRT.find(_rName); + if (aSearch == m_aDriversRT.end()) + throwNoSuchElementException(); + + return aSearch->second.get(); +} + + +void SAL_CALL OSDBCDriverManager::registerObject( const OUString& _rName, const Reference< XInterface >& _rxObject ) +{ + MutexGuard aGuard(m_aMutex); + + m_aEventLogger.log( LogLevel::INFO, + "attempt to register new driver for name $1$", + _rName + ); + + DriverCollection::const_iterator aSearch = m_aDriversRT.find(_rName); + if (aSearch != m_aDriversRT.end()) + throw ElementExistException(); + Reference< XDriver > xNewDriver(_rxObject, UNO_QUERY); + if (!xNewDriver.is()) + throw IllegalArgumentException(); + + m_aDriversRT.emplace(_rName, xNewDriver); + + m_aEventLogger.log( LogLevel::INFO, + "new driver registered for name $1$", + _rName + ); +} + + +void SAL_CALL OSDBCDriverManager::revokeObject( const OUString& _rName ) +{ + MutexGuard aGuard(m_aMutex); + + m_aEventLogger.log( LogLevel::INFO, + "attempt to revoke driver for name $1$", + _rName + ); + + DriverCollection::iterator aSearch = m_aDriversRT.find(_rName); + if (aSearch == m_aDriversRT.end()) + throwNoSuchElementException(); + + m_aDriversRT.erase(aSearch); // we already have the iterator so we could use it + + m_aEventLogger.log( LogLevel::INFO, + "driver revoked for name $1$", + _rName + ); +} + + +Reference< XDriver > SAL_CALL OSDBCDriverManager::getDriverByURL( const OUString& _rURL ) +{ + m_aEventLogger.log( LogLevel::INFO, + "driver requested for URL $1$", + _rURL + ); + + Reference< XDriver > xDriver( implGetDriverForURL( _rURL ) ); + + if ( xDriver.is() ) + m_aEventLogger.log( LogLevel::INFO, + "driver obtained for URL $1$", + _rURL + ); + + return xDriver; +} + + +Reference< XDriver > OSDBCDriverManager::implGetDriverForURL(const OUString& _rURL) +{ + Reference< XDriver > xReturn; + + { + const OUString sDriverFactoryName = m_aDriverConfig.getDriverFactoryName(_rURL); + + EqualDriverAccessToName aEqual(sDriverFactoryName); + DriverAccessArray::const_iterator aFind = std::find_if(m_aDriversBS.begin(),m_aDriversBS.end(),aEqual); + if ( aFind == m_aDriversBS.end() ) + { + // search all bootstrapped drivers + aFind = std::find_if( + m_aDriversBS.begin(), // begin of search range + m_aDriversBS.end(), // end of search range + [&_rURL, this] (const DriverAccessArray::value_type& driverAccess) { + // extract the driver from the access, then ask the resulting driver for acceptance + const DriverAccess& ensuredAccess = EnsureDriver(m_xContext)(driverAccess); + const Reference<XDriver> driver = ExtractDriverFromAccess()(ensuredAccess); + return AcceptsURL(_rURL)(driver); + }); + } // if ( m_aDriversBS.find(sDriverFactoryName ) == m_aDriversBS.end() ) + else + { + EnsureDriver aEnsure( m_xContext ); + aEnsure(*aFind); + } + + // found something? + if ( m_aDriversBS.end() != aFind && aFind->xDriver.is() && aFind->xDriver->acceptsURL(_rURL) ) + xReturn = aFind->xDriver; + } + + if ( !xReturn.is() ) + { + // no -> search the runtime drivers + DriverCollection::const_iterator aPos = std::find_if( + m_aDriversRT.begin(), // begin of search range + m_aDriversRT.end(), // end of search range + [&_rURL] (const DriverCollection::value_type& element) { + // extract the driver from the collection element, then ask the resulting driver for acceptance + const Reference<XDriver> driver = ExtractDriverFromCollectionElement()(element); + return AcceptsURL(_rURL)(driver); + }); + + if ( m_aDriversRT.end() != aPos ) + xReturn = aPos->second; + } + + return xReturn; +} + +} // namespace drivermanager + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/manager/mdrivermanager.hxx b/connectivity/source/manager/mdrivermanager.hxx new file mode 100644 index 000000000..21e7bb5df --- /dev/null +++ b/connectivity/source/manager/mdrivermanager.hxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_MANAGER_MDRIVERMANAGER_HXX +#define INCLUDED_CONNECTIVITY_SOURCE_MANAGER_MDRIVERMANAGER_HXX + +#include <sal/config.h> + +#include <map> +#include <vector> + +#include <com/sun/star/sdbc/XDriverManager2.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XNamingService.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> + +#include <cppuhelper/implbase.hxx> +#include <comphelper/logging.hxx> +#include <osl/mutex.hxx> +#include <connectivity/DriversConfig.hxx> + +namespace drivermanager +{ + + typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > DriverCollection; + + struct DriverAccess + { + OUString sImplementationName; /// the implementation name of the driver + css::uno::Reference< css::sdbc::XDriver > xDriver; /// the driver itself + css::uno::Reference< css::lang::XSingleComponentFactory > xComponentFactory; /// the factory to create the driver component (if not already done so) + }; + + + // OSDBCDriverManager - the one-instance service for managing SDBC drivers + + typedef ::cppu::WeakImplHelper< css::sdbc::XDriverManager2 + , css::lang::XServiceInfo + , css::uno::XNamingService + > OSDBCDriverManager_Base; + + class OSDBCDriverManager final : public OSDBCDriverManager_Base + { + friend class ODriverEnumeration; + + ::osl::Mutex m_aMutex; + css::uno::Reference<css::uno::XComponentContext> m_xContext; + ::comphelper::EventLogger m_aEventLogger; + + typedef std::vector<DriverAccess> DriverAccessArray; + DriverAccessArray m_aDriversBS; + + // for drivers registered at runtime (not bootstrapped) we don't require an XServiceInfo interface, + // so we have to remember their impl-name in another way + typedef std::map< OUString, css::uno::Reference< css::sdbc::XDriver > > DriverCollection; + DriverCollection m_aDriversRT; + + ::connectivity::DriversConfig m_aDriverConfig; + sal_Int32 m_nLoginTimeout; + + explicit OSDBCDriverManager( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext ); + virtual ~OSDBCDriverManager() override; + + public: + + // XDriverManager + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& url ) override; + virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnectionWithInfo( const OUString& url, const css::uno::Sequence< css::beans::PropertyValue >& info ) override; + virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override; + virtual sal_Int32 SAL_CALL getLoginTimeout( ) override; + + // XDriverAccess + virtual css::uno::Reference< css::sdbc::XDriver > SAL_CALL getDriverByURL( const OUString& url ) override; + + // XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override; + + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static OUString getImplementationName_static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_static( ); + /// @throws css::uno::RuntimeException + static OUString getSingletonName_static( ); + static css::uno::Reference< css::uno::XInterface > Create( const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxContext ); + + // XNamingService + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getRegisteredObject( const OUString& Name ) override; + virtual void SAL_CALL registerObject( const OUString& Name, const css::uno::Reference< css::uno::XInterface >& Object ) override; + virtual void SAL_CALL revokeObject( const OUString& Name ) override; + + private: + css::uno::Reference< css::sdbc::XDriver > implGetDriverForURL(const OUString& _rURL); + + /** retrieve the driver order preferences from the configuration and + sort m_aDriversBS accordingly. + */ + void initializeDriverPrecedence(); + + void bootstrapDrivers(); + }; + +} // namespace drivermanager + +#endif // INCLUDED_CONNECTIVITY_SOURCE_MANAGER_MDRIVERMANAGER_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/manager/mregistration.cxx b/connectivity/source/manager/mregistration.cxx new file mode 100644 index 000000000..c78d3ec6d --- /dev/null +++ b/connectivity/source/manager/mregistration.cxx @@ -0,0 +1,61 @@ +/* -*- 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 "mdrivermanager.hxx" + +#include <cppuhelper/factory.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +extern "C" +{ + + +SAL_DLLPUBLIC_EXPORT void* sdbc2_component_getFactory(const char* _pImplName, void * _pServiceManager, void* /*_pRegistryKey*/) +{ + void* pRet = nullptr; + + if (::drivermanager::OSDBCDriverManager::getImplementationName_static().equalsAscii(_pImplName)) + { + Reference< XSingleServiceFactory > xFactory( + ::cppu::createOneInstanceFactory( + static_cast<css::lang::XMultiServiceFactory *>( + _pServiceManager), + ::drivermanager::OSDBCDriverManager::getImplementationName_static(), + ::drivermanager::OSDBCDriverManager::Create, + ::drivermanager::OSDBCDriverManager::getSupportedServiceNames_static() + ) + ); + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} + +} // extern "C" + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/manager/sdbc2.component b/connectivity/source/manager/sdbc2.component new file mode 100644 index 000000000..b192bebad --- /dev/null +++ b/connectivity/source/manager/sdbc2.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="sdbc2" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.OSDBCDriverManager"> + <service name="com.sun.star.sdbc.DriverManager"/> + </implementation> +</component> diff --git a/connectivity/source/parse/PColumn.cxx b/connectivity/source/parse/PColumn.cxx new file mode 100644 index 000000000..cf9b17ee5 --- /dev/null +++ b/connectivity/source/parse/PColumn.cxx @@ -0,0 +1,271 @@ +/* -*- 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/PColumn.hxx> +#include <TConnection.hxx> + +#include <comphelper/types.hxx> + +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +using namespace ::comphelper; +using namespace connectivity; +using namespace dbtools; +using namespace connectivity::parse; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; + + +OParseColumn::OParseColumn(const Reference<XPropertySet>& _xColumn, bool _bCase) + : connectivity::sdbcx::OColumn( getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))) + , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))) + , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))) + , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))) + , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))) + , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))) + , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))) + , getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) + , getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))) + , false + , getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))) + , _bCase + , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))) + , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))) + , getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))) + ) + , m_bFunction(false) + , m_bDbasePrecisionChanged(false) + , m_bAggregateFunction(false) + , m_bIsSearchable( true ) +{ + construct(); +} + + +OParseColumn::OParseColumn( const OUString& Name, + const OUString& TypeName, + const OUString& DefaultValue, + const OUString& Description, + sal_Int32 IsNullable, + sal_Int32 Precision, + sal_Int32 Scale, + sal_Int32 Type, + bool IsAutoIncrement, + bool IsCurrency, + bool _bCase, + const OUString& CatalogName, + const OUString& SchemaName, + const OUString& TableName + ) : connectivity::sdbcx::OColumn(Name, + TypeName, + DefaultValue, + Description, + IsNullable, + Precision, + Scale, + Type, + IsAutoIncrement, + false, + IsCurrency, + _bCase, + CatalogName, + SchemaName, + TableName) + , m_bFunction(false) + , m_bDbasePrecisionChanged(false) + , m_bAggregateFunction(false) + , m_bIsSearchable( true ) +{ + construct(); +} + + +::rtl::Reference< OSQLColumns > OParseColumn::createColumnsForResultSet( const Reference< XResultSetMetaData >& _rxResMetaData, + const Reference< XDatabaseMetaData >& _rxDBMetaData,const Reference< XNameAccess>& i_xQueryColumns ) +{ + sal_Int32 nColumnCount = _rxResMetaData->getColumnCount(); + ::rtl::Reference aReturn( new OSQLColumns ); aReturn->reserve( nColumnCount ); + + StringMap aColumnMap; + for ( sal_Int32 i = 1; i <= nColumnCount; ++i ) + { + OParseColumn* pColumn = createColumnForResultSet( _rxResMetaData, _rxDBMetaData, i,aColumnMap ); + aReturn->push_back( pColumn ); + if ( i_xQueryColumns.is() && i_xQueryColumns->hasByName(pColumn->getRealName()) ) + { + Reference<XPropertySet> xColumn(i_xQueryColumns->getByName(pColumn->getRealName()),UNO_QUERY_THROW); + OUString sLabel; + xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LABEL)) >>= sLabel; + if ( !sLabel.isEmpty() ) + pColumn->setLabel(sLabel); + } + } + + return aReturn; +} + + +OParseColumn* OParseColumn::createColumnForResultSet( const Reference< XResultSetMetaData >& _rxResMetaData, + const Reference< XDatabaseMetaData >& _rxDBMetaData, sal_Int32 _nColumnPos, StringMap& _rColumns ) +{ + OUString sLabel = _rxResMetaData->getColumnLabel( _nColumnPos ); + // retrieve the name of the column + // check for duplicate entries + if(_rColumns.find(sLabel) != _rColumns.end()) + { + OUString sAlias(sLabel); + sal_Int32 searchIndex=1; + while(_rColumns.find(sAlias) != _rColumns.end()) + { + sAlias = sLabel + OUString::number(searchIndex++); + } + sLabel = sAlias; + } + _rColumns.emplace(sLabel,0); + OParseColumn* pColumn = new OParseColumn( + sLabel, + _rxResMetaData->getColumnTypeName( _nColumnPos ), + OUString(), + OUString(), + _rxResMetaData->isNullable( _nColumnPos ), + _rxResMetaData->getPrecision( _nColumnPos ), + _rxResMetaData->getScale( _nColumnPos ), + _rxResMetaData->getColumnType( _nColumnPos ), + _rxResMetaData->isAutoIncrement( _nColumnPos ), + _rxResMetaData->isCurrency( _nColumnPos ), + _rxDBMetaData->supportsMixedCaseQuotedIdentifiers(), + _rxResMetaData->getCatalogName( _nColumnPos ), + _rxResMetaData->getSchemaName( _nColumnPos ), + _rxResMetaData->getTableName( _nColumnPos ) + ); + pColumn->setIsSearchable( _rxResMetaData->isSearchable( _nColumnPos ) ); + pColumn->setRealName(_rxResMetaData->getColumnName( _nColumnPos )); + pColumn->setLabel(sLabel); + return pColumn; +} + + +OParseColumn::~OParseColumn() +{ +} + +void OParseColumn::construct() +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION), PROPERTY_ID_FUNCTION, 0, &m_bFunction, cppu::UnoType<decltype(m_bFunction)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_AGGREGATEFUNCTION), PROPERTY_ID_AGGREGATEFUNCTION, 0, &m_bAggregateFunction, cppu::UnoType<decltype(m_bAggregateFunction)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME), PROPERTY_ID_REALNAME, 0, &m_aRealName, cppu::UnoType<decltype(m_aRealName)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DBASEPRECISIONCHANGED), PROPERTY_ID_DBASEPRECISIONCHANGED, 0, &m_bDbasePrecisionChanged, cppu::UnoType<decltype(m_bDbasePrecisionChanged)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISSEARCHABLE), PROPERTY_ID_ISSEARCHABLE, 0, &m_bIsSearchable, cppu::UnoType<decltype(m_bIsSearchable)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LABEL), PROPERTY_ID_LABEL, 0, &m_sLabel, cppu::UnoType<decltype(m_sLabel)>::get()); +} + +::cppu::IPropertyArrayHelper* OParseColumn::createArrayHelper() const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & SAL_CALL OParseColumn::getInfoHelper() +{ + OSL_ENSURE( !isNew(), "OParseColumn::getInfoHelper: a *new* ParseColumn?" ); + return *OParseColumn_PROP::getArrayHelper(); +} + + +OOrderColumn::OOrderColumn( const Reference<XPropertySet>& _xColumn, const OUString& i_rOriginatingTableName, + bool _bCase, bool _bAscending ) + : connectivity::sdbcx::OColumn( + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))), + getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))), + getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))), + getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))), + getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))), + getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))), + false, + getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))), + _bCase, + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))), + i_rOriginatingTableName + ) + ,m_bAscending(_bAscending) +{ + construct(); +} + + +OOrderColumn::OOrderColumn( const Reference<XPropertySet>& _xColumn, bool _bCase, bool _bAscending ) + : connectivity::sdbcx::OColumn( + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))), + getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))), + getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))), + getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))), + getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))), + getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))), + false, + getBOOL(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))), + _bCase, + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))), + getString(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))) + ) + ,m_bAscending(_bAscending) +{ + construct(); +} + + +OOrderColumn::~OOrderColumn() +{ +} + + +void OOrderColumn::construct() +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING, + PropertyAttribute::READONLY, const_cast< bool* >( &m_bAscending ), cppu::UnoType<decltype(m_bAscending)>::get() ); +} + +::cppu::IPropertyArrayHelper* OOrderColumn::createArrayHelper() const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & SAL_CALL OOrderColumn::getInfoHelper() +{ + OSL_ENSURE( !isNew(), "OOrderColumn::getInfoHelper: a *new* OrderColumn?" ); + return *OOrderColumn_PROP::getArrayHelper(); +} + +css::uno::Sequence< OUString > SAL_CALL OOrderColumn::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdb.OrderColumn" }; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/parse/internalnode.cxx b/connectivity/source/parse/internalnode.cxx new file mode 100644 index 000000000..ccee05746 --- /dev/null +++ b/connectivity/source/parse/internalnode.cxx @@ -0,0 +1,64 @@ +/* -*- 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/sqlparse.hxx> +#include <connectivity/internalnode.hxx> + +using namespace connectivity; + + +OSQLInternalNode::OSQLInternalNode(const char* pNewValue, + SQLNodeType eNodeType, + sal_uInt32 nNodeID) + : OSQLParseNode(pNewValue,eNodeType,nNodeID) +{ + OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized"); + (*OSQLParser::s_pGarbageCollector)->push_back(this); +} + + +OSQLInternalNode::OSQLInternalNode(const OString &NewValue, + SQLNodeType eNodeType, + sal_uInt32 nNodeID) + :OSQLParseNode(NewValue,eNodeType,nNodeID) +{ + OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized"); + (*OSQLParser::s_pGarbageCollector)->push_back(this); +} + + +OSQLInternalNode::OSQLInternalNode(const OUString &NewValue, + SQLNodeType eNodeType, + sal_uInt32 nNodeID) + :OSQLParseNode(NewValue,eNodeType,nNodeID) +{ + OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized"); + (*OSQLParser::s_pGarbageCollector)->push_back(this); +} + + +OSQLInternalNode::~OSQLInternalNode() +{ + // remove the node from the garbage list + + OSL_ENSURE(OSQLParser::s_pGarbageCollector, "Collector not initialized"); + (*OSQLParser::s_pGarbageCollector)->erase(this); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/parse/sqlbison.y b/connectivity/source/parse/sqlbison.y new file mode 100644 index 000000000..d14f36e77 --- /dev/null +++ b/connectivity/source/parse/sqlbison.y @@ -0,0 +1,4829 @@ +%glr-parser +%token-table +%{ +/* + * 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 <vector> +#include <string.h> + +#include <connectivity/sqlnode.hxx> +#include <connectivity/sqlparse.hxx> +#include <connectivity/sqlbison_exports.hxx> +#include <connectivity/sqlscan.hxx> +#include <connectivity/internalnode.hxx> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormats.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/i18n/KParseType.hpp> +#include <com/sun/star/i18n/KParseTokens.hpp> + +#include <osl/diagnose.h> +#include "connectivity/dbconversion.hxx" +#include <rtl/ustrbuf.hxx> +#include <sal/macros.h> +#include <sal/log.hxx> + +#if defined _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4324) // structure was padded due to alignment specifier +#pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels +#pragma warning(disable: 4702) // unreachable code +#endif + +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wwrite-strings" +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +inline connectivity::OSQLInternalNode* newNode(const char* pNewValue, + const connectivity::SQLNodeType eNodeType, + const sal_uInt32 nNodeID = 0); + +inline connectivity::OSQLInternalNode* newNode(const OString& _newValue, + const connectivity::SQLNodeType eNodeType, + const sal_uInt32 nNodeID = 0); + +inline connectivity::OSQLInternalNode* newNode(const OUString& _newValue, + const connectivity::SQLNodeType eNodeType, + const sal_uInt32 nNodeID = 0); + + +// yyi is the internal number of the rule that is currently being reduced +// This can be mapped to external rule number via the yyrmap. +#define SQL_NEW_RULE newNode("", SQLNodeType::Rule, yyr1[yyn]) +#define SQL_NEW_LISTRULE newNode("", SQLNodeType::ListRule, yyr1[yyn]) +#define SQL_NEW_COMMALISTRULE newNode("", SQLNodeType::CommaListRule, yyr1[yyn]) + + +extern connectivity::OSQLParser* xxx_pGLOBAL_SQLPARSER; + +#define YYERROR_VERBOSE + +#define SQLyyerror(s) \ +{ \ + xxx_pGLOBAL_SQLPARSER->error(s); \ +} + +using namespace connectivity; +#define SQLyylex xxx_pGLOBAL_SQLPARSER->SQLlex +%} + /* symbolic tokens */ + +%union { + connectivity::OSQLParseNode * pParseNode; +} +%type <pParseNode> '(' ')' ',' ':' ';' '?' '[' ']' '{' '}' '.' 'K' 'M' 'G' 'T' 'P' + +%token <pParseNode> SQL_TOKEN_STRING SQL_TOKEN_ACCESS_DATE SQL_TOKEN_INT SQL_TOKEN_REAL_NUM +%token <pParseNode> SQL_TOKEN_INTNUM SQL_TOKEN_APPROXNUM SQL_TOKEN_NOT SQL_TOKEN_NAME + + +%nonassoc <pParseNode> SQL_TOKEN_UMINUS + + + + /* literal keyword tokens */ + +%token <pParseNode> SQL_TOKEN_ALL SQL_TOKEN_ALTER SQL_TOKEN_AMMSC SQL_TOKEN_ANY SQL_TOKEN_AS SQL_TOKEN_ASC SQL_TOKEN_AT SQL_TOKEN_AUTHORIZATION SQL_TOKEN_AVG + +%token <pParseNode> SQL_TOKEN_BETWEEN SQL_TOKEN_BIT SQL_TOKEN_BOTH SQL_TOKEN_BY + +%token <pParseNode> SQL_TOKEN_CAST SQL_TOKEN_CHARACTER SQL_TOKEN_CHECK SQL_TOKEN_COLLATE SQL_TOKEN_COMMIT SQL_TOKEN_CONTINUE SQL_TOKEN_CONVERT SQL_TOKEN_COUNT SQL_TOKEN_CREATE SQL_TOKEN_CROSS +%token <pParseNode> SQL_TOKEN_CURRENT SQL_TOKEN_CURSOR + +%token <pParseNode> SQL_TOKEN_DATE SQL_TOKEN_DATEVALUE SQL_TOKEN_DAY SQL_TOKEN_DEC SQL_TOKEN_DECIMAL SQL_TOKEN_DECLARE SQL_TOKEN_DEFAULT SQL_TOKEN_DELETE SQL_TOKEN_DESC +%token <pParseNode> SQL_TOKEN_DISTINCT SQL_TOKEN_DOUBLE SQL_TOKEN_DROP + +%token <pParseNode> SQL_TOKEN_ESCAPE SQL_TOKEN_EXCEPT SQL_TOKEN_EXISTS SQL_TOKEN_FALSE SQL_TOKEN_FETCH SQL_TOKEN_FLOAT SQL_TOKEN_FOR SQL_TOKEN_FOREIGN SQL_TOKEN_FOUND SQL_TOKEN_FROM SQL_TOKEN_FULL + +%token <pParseNode> SQL_TOKEN_GRANT SQL_TOKEN_GROUP SQL_TOKEN_HAVING SQL_TOKEN_IN SQL_TOKEN_INDICATOR SQL_TOKEN_INNER SQL_TOKEN_INTEGER SQL_TOKEN_INTO SQL_TOKEN_IS SQL_TOKEN_INTERSECT + +%left <pParseNode> SQL_TOKEN_JOIN +%token <pParseNode> SQL_TOKEN_KEY SQL_TOKEN_LEADING SQL_TOKEN_LIKE SQL_TOKEN_LOCAL SQL_TOKEN_LOWER +%token <pParseNode> SQL_TOKEN_MAX SQL_TOKEN_MIN SQL_TOKEN_NATURAL SQL_TOKEN_NCHAR SQL_TOKEN_NULL SQL_TOKEN_NUMERIC + +%token <pParseNode> SQL_TOKEN_OCTET_LENGTH SQL_TOKEN_OF SQL_TOKEN_ON SQL_TOKEN_OPTION SQL_TOKEN_ORDER SQL_TOKEN_OUTER + +%token <pParseNode> SQL_TOKEN_PRECISION SQL_TOKEN_PRIMARY SQL_TOKEN_PRIVILEGES SQL_TOKEN_PROCEDURE SQL_TOKEN_PUBLIC +%token <pParseNode> SQL_TOKEN_REAL SQL_TOKEN_REFERENCES SQL_TOKEN_ROLLBACK + +%token <pParseNode> SQL_TOKEN_SCHEMA SQL_TOKEN_SELECT SQL_TOKEN_SET SQL_TOKEN_SIZE SQL_TOKEN_SMALLINT SQL_TOKEN_SOME SQL_TOKEN_SQLCODE SQL_TOKEN_SQLERROR SQL_TOKEN_SUM + +%token <pParseNode> SQL_TOKEN_TABLE SQL_TOKEN_TIME SQL_TOKEN_TIMESTAMP SQL_TOKEN_TIMEZONE_HOUR SQL_TOKEN_TIMEZONE_MINUTE SQL_TOKEN_TO SQL_TOKEN_TRAILING SQL_TOKEN_TRANSLATE SQL_TOKEN_TRIM SQL_TOKEN_TRUE SQL_TOKEN_UNION +%token <pParseNode> SQL_TOKEN_UNIQUE SQL_TOKEN_UNKNOWN SQL_TOKEN_UPDATE SQL_TOKEN_UPPER SQL_TOKEN_USAGE SQL_TOKEN_USER SQL_TOKEN_USING SQL_TOKEN_VALUES SQL_TOKEN_VIEW +%token <pParseNode> SQL_TOKEN_WHERE SQL_TOKEN_WITH SQL_TOKEN_WORK SQL_TOKEN_ZONE + +/* ODBC KEYWORDS */ +%token <pParseNode> SQL_TOKEN_CALL SQL_TOKEN_D SQL_TOKEN_FN SQL_TOKEN_T SQL_TOKEN_TS SQL_TOKEN_OJ +/* string functions */ +%token <pParseNode> SQL_TOKEN_ASCII SQL_TOKEN_BIT_LENGTH SQL_TOKEN_CHAR SQL_TOKEN_CHAR_LENGTH SQL_TOKEN_SQL_TOKEN_INTNUM +%token <pParseNode> SQL_TOKEN_CONCAT +%token <pParseNode> SQL_TOKEN_DIFFERENCE SQL_TOKEN_INSERT SQL_TOKEN_LCASE SQL_TOKEN_LEFT SQL_TOKEN_LENGTH SQL_TOKEN_LOCATE +%token <pParseNode> SQL_TOKEN_LOCATE_2 SQL_TOKEN_LTRIM SQL_TOKEN_POSITION SQL_TOKEN_REPEAT SQL_TOKEN_REPLACE +%token <pParseNode> SQL_TOKEN_RIGHT SQL_TOKEN_RTRIM SQL_TOKEN_SOUNDEX SQL_TOKEN_SPACE SQL_TOKEN_SUBSTRING SQL_TOKEN_UCASE + +/* time and date functions */ +%token <pParseNode> SQL_TOKEN_CURRENT_DATE SQL_TOKEN_CURRENT_TIME SQL_TOKEN_CURRENT_TIMESTAMP SQL_TOKEN_CURDATE SQL_TOKEN_CURTIME +%token <pParseNode> SQL_TOKEN_DAYNAME SQL_TOKEN_DAYOFMONTH SQL_TOKEN_DAYOFWEEK SQL_TOKEN_DAYOFYEAR SQL_TOKEN_EXTRACT +%token <pParseNode> SQL_TOKEN_HOUR SQL_TOKEN_MILLISECOND SQL_TOKEN_MINUTE SQL_TOKEN_MONTH SQL_TOKEN_MONTHNAME SQL_TOKEN_NOW SQL_TOKEN_QUARTER SQL_TOKEN_DATEDIFF +%token <pParseNode> SQL_TOKEN_SECOND SQL_TOKEN_TIMESTAMPADD SQL_TOKEN_TIMESTAMPDIFF SQL_TOKEN_TIMEVALUE SQL_TOKEN_WEEK SQL_TOKEN_WEEKDAY SQL_TOKEN_YEAR SQL_TOKEN_YEARDAY + +/* numeric functions */ +%token <pParseNode> SQL_TOKEN_ABS SQL_TOKEN_ACOS SQL_TOKEN_ASIN SQL_TOKEN_ATAN SQL_TOKEN_ATAN2 SQL_TOKEN_CEILING +%token <pParseNode> SQL_TOKEN_COS SQL_TOKEN_COT SQL_TOKEN_DEGREES SQL_TOKEN_EXP SQL_TOKEN_FLOOR SQL_TOKEN_LOGF SQL_TOKEN_LOG SQL_TOKEN_LN +%token <pParseNode> SQL_TOKEN_LOG10 SQL_TOKEN_MOD SQL_TOKEN_PI SQL_TOKEN_POWER SQL_TOKEN_RADIANS SQL_TOKEN_RAND SQL_TOKEN_ROUNDMAGIC +%token <pParseNode> SQL_TOKEN_ROUND SQL_TOKEN_SIGN SQL_TOKEN_SIN SQL_TOKEN_SQRT SQL_TOKEN_TAN SQL_TOKEN_TRUNCATE + +// computational operation +%token <pParseNode> SQL_TOKEN_EVERY SQL_TOKEN_INTERSECTION SQL_TOKEN_FUSION SQL_TOKEN_COLLECT SQL_TOKEN_VAR_POP SQL_TOKEN_VAR_SAMP +%token <pParseNode> SQL_TOKEN_STDDEV_SAMP SQL_TOKEN_STDDEV_POP + +%token <pParseNode> SQL_TOKEN_RANK SQL_TOKEN_DENSE_RANK SQL_TOKEN_PERCENT_RANK SQL_TOKEN_CUME_DIST SQL_TOKEN_PERCENTILE_CONT SQL_TOKEN_PERCENTILE_DISC SQL_TOKEN_WITHIN SQL_TOKEN_ARRAY_AGG +%token <pParseNode> SQL_TOKEN_CASE SQL_TOKEN_THEN SQL_TOKEN_END SQL_TOKEN_NULLIF SQL_TOKEN_COALESCE SQL_TOKEN_WHEN SQL_TOKEN_ELSE +%token <pParseNode> SQL_TOKEN_BEFORE SQL_TOKEN_AFTER SQL_TOKEN_INSTEAD SQL_TOKEN_EACH SQL_TOKEN_REFERENCING SQL_TOKEN_BEGIN SQL_TOKEN_ATOMIC SQL_TOKEN_TRIGGER SQL_TOKEN_ROW SQL_TOKEN_STATEMENT +%token <pParseNode> SQL_TOKEN_NEW SQL_TOKEN_OLD +%token <pParseNode> SQL_TOKEN_VALUE SQL_TOKEN_CURRENT_CATALOG SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP SQL_TOKEN_CURRENT_PATH SQL_TOKEN_CURRENT_ROLE SQL_TOKEN_CURRENT_SCHEMA SQL_TOKEN_CURRENT_USER +%token <pParseNode> SQL_TOKEN_SESSION_USER SQL_TOKEN_SYSTEM_USER SQL_TOKEN_VARCHAR SQL_TOKEN_VARBINARY SQL_TOKEN_VARYING SQL_TOKEN_OBJECT SQL_TOKEN_NCLOB SQL_TOKEN_NATIONAL +%token <pParseNode> SQL_TOKEN_LARGE SQL_TOKEN_CLOB SQL_TOKEN_BLOB SQL_TOKEN_BIGINT SQL_TOKEN_BINARY SQL_TOKEN_WITHOUT SQL_TOKEN_BOOLEAN SQL_TOKEN_INTERVAL +// window function +%token <pParseNode> SQL_TOKEN_OVER SQL_TOKEN_ROW_NUMBER SQL_TOKEN_NTILE SQL_TOKEN_LEAD SQL_TOKEN_LAG SQL_TOKEN_RESPECT SQL_TOKEN_IGNORE SQL_TOKEN_NULLS +%token <pParseNode> SQL_TOKEN_FIRST_VALUE SQL_TOKEN_LAST_VALUE SQL_TOKEN_NTH_VALUE SQL_TOKEN_FIRST SQL_TOKEN_LAST +%token <pParseNode> SQL_TOKEN_EXCLUDE SQL_TOKEN_OTHERS SQL_TOKEN_TIES SQL_TOKEN_FOLLOWING SQL_TOKEN_UNBOUNDED SQL_TOKEN_PRECEDING SQL_TOKEN_RANGE SQL_TOKEN_ROWS +%token <pParseNode> SQL_TOKEN_PARTITION SQL_TOKEN_WINDOW SQL_TOKEN_NO +// LIMIT and OFFSEt +%token <pParseNode> SQL_TOKEN_LIMIT SQL_TOKEN_OFFSET SQL_TOKEN_NEXT SQL_TOKEN_ONLY + + /* operators */ +%left SQL_TOKEN_NAME +%left <pParseNode> SQL_TOKEN_OR +%left <pParseNode> SQL_TOKEN_AND + +%left <pParseNode> SQL_LESSEQ SQL_GREATEQ SQL_NOTEQUAL SQL_LESS SQL_GREAT SQL_EQUAL /* '<' '>' = <> < > <= >= != */ +%left <pParseNode> '+' '-' SQL_CONCAT +%left <pParseNode> '*' '/' +%left SQL_TOKEN_NATURAL SQL_TOKEN_CROSS SQL_TOKEN_FULL SQL_TOKEN_LEFT SQL_TOKEN_RIGHT +%left ')' +%right '=' +%right '.' +%right '(' + + +%token <pParseNode> SQL_TOKEN_INVALIDSYMBOL + +/*%type <pParseNode> sql_single_statement */ + +%type <pParseNode> sql /*schema */ +%type <pParseNode> column_def_opt_list column_def_opt table_constraint_def column_commalist +%type <pParseNode> view_def opt_with_check_option opt_column_commalist privilege_def +%type <pParseNode> opt_with_grant_option privileges operation_commalist operation +%type <pParseNode> grantee_commalist grantee opt_order_by_clause ordering_spec_commalist +%type <pParseNode> ordering_spec opt_asc_desc manipulative_statement commit_statement +%type <pParseNode> /*delete_statement_positioned*/ delete_statement_searched fetch_statement +%type <pParseNode> insert_statement values_or_query_spec +%type <pParseNode> rollback_statement select_statement_into opt_all_distinct +%type <pParseNode> /*update_statement_positioned*/ assignment_commalist assignment +%type <pParseNode> update_statement_searched target_commalist target opt_where_clause +%type <pParseNode> select_statement selection table_exp from_clause table_ref_commalist table_ref +%type <pParseNode> where_clause opt_group_by_clause column_ref_commalist opt_having_clause +%type <pParseNode> search_condition predicate comparison_predicate comparison_predicate_part_2 between_predicate between_predicate_part_2 +%type <pParseNode> like_predicate opt_escape test_for_null null_predicate_part_2 in_predicate in_predicate_part_2 character_like_predicate_part_2 other_like_predicate_part_2 +%type <pParseNode> all_or_any_predicate any_all_some existence_test subquery quantified_comparison_predicate_part_2 +%type <pParseNode> scalar_exp_commalist parameter_ref literal parenthesized_boolean_value_expression +%type <pParseNode> column_ref data_type column cursor parameter range_variable user /*like_check*/ +/* new rules at OJ */ +%type <pParseNode> derived_column as_clause table_name num_primary term num_value_exp +%type <pParseNode> value_exp_primary num_value_fct unsigned_value_spec cast_spec set_fct_spec scalar_subquery +%type <pParseNode> position_exp extract_exp length_exp general_value_spec +%type <pParseNode> general_set_fct set_fct_type query_exp non_join_query_exp joined_table +%type <pParseNode> non_join_query_term non_join_query_primary simple_table +%type <pParseNode> table_value_const_list row_value_constructor /*row_value_const_list*/ row_value_constructor_elem +%type <pParseNode> qualified_join value_exp query_term join_type outer_join_type join_condition boolean_term +%type <pParseNode> boolean_factor boolean_primary named_columns_join join_spec +%type <pParseNode> cast_operand cast_target factor datetime_value_exp /*interval_value_exp*/ datetime_term datetime_factor +%type <pParseNode> datetime_primary datetime_value_fct time_zone time_zone_specifier /*interval_term*/ interval_qualifier +%type <pParseNode> start_field non_second_datetime_field end_field single_datetime_field extract_field datetime_field time_zone_field +%type <pParseNode> char_length_exp octet_length_exp bit_length_exp select_sublist string_value_exp +%type <pParseNode> char_value_exp concatenation char_factor char_primary string_value_fct char_substring_fct fold +%type <pParseNode> form_conversion char_translation trim_fct trim_operands trim_spec bit_value_fct bit_substring_fct op_column_commalist +%type <pParseNode> /*bit_concatenation*/ bit_value_exp bit_factor bit_primary collate_clause char_value_fct unique_spec value_exp_commalist in_predicate_value unique_test update_source +%type <pParseNode> function_arg_commalist3 string_function_3Argument function_arg_commalist4 string_function_4Argument function_arg_commalist2 string_function_1Argument string_function_2Argument +%type <pParseNode> date_function_0Argument date_function_1Argument function_name12 function_name23 function_name1 function_name2 function_name3 function_name0 numeric_function_0Argument numeric_function_1Argument numeric_function_2Argument +%type <pParseNode> all query_primary sql_not for_length upper_lower comparison column_val cross_union /*opt_schema_element_list*/ +%type <pParseNode> /*op_authorization op_schema*/ nil_fkt schema_element base_table_def base_table_element base_table_element_commalist +%type <pParseNode> column_def odbc_fct_spec odbc_call_spec odbc_fct_type op_parameter union_statement +%type <pParseNode> op_odbc_call_parameter odbc_parameter_commalist odbc_parameter function_args_commalist function_arg +%type <pParseNode> catalog_name schema_name table_node numeric_function string_function function_name date_function table_primary_as_range_column opt_as +%type <pParseNode> ordered_set_function inverse_distribution_function hypothetical_set_function hypothetical_set_function_value_expression_list rank_function_type within_group_specification inverse_distribution_function_type array_aggregate_function inverse_distribution_function_argument +%type <pParseNode> case_expression else_clause result_expression result case_abbreviation case_specification searched_when_clause simple_when_clause searched_case simple_case +%type <pParseNode> when_operand_list when_operand case_operand +%type <pParseNode> trigger_definition trigger_name trigger_action_time trigger_event transition_table_or_variable_list triggered_action trigger_column_list triggered_when_clause triggered_SQL_statement SQL_procedure_statement old_transition_variable_name new_transition_variable_name +%type <pParseNode> op_referencing op_trigger_columnlist op_triggered_action_for opt_row trigger_for SQL_procedure_statement_list transition_table_or_variable old_transition_table_name new_transition_table_name transition_table_name +%type <pParseNode> searched_when_clause_list simple_when_clause_list predefined_type opt_char_set_spec opt_collate_clause character_string_type national_character_string_type +%type <pParseNode> binary_string_type numeric_type boolean_type datetime_type interval_type opt_paren_precision paren_char_length opt_paren_char_large_length paren_character_large_object_length +%type <pParseNode> large_object_length opt_multiplier character_large_object_type national_character_large_object_type binary_large_object_string_type opt_with_or_without_time_zone +%type <pParseNode> approximate_numeric_type exact_numeric_type opt_paren_precision_scale +/* window function rules */ +%type <pParseNode> window_function window_function_type ntile_function number_of_tiles lead_or_lag_function lead_or_lag lead_or_lag_extent offset default_expression null_treatment +%type <pParseNode> first_or_last_value_function first_or_last_value nth_value_function nth_row from_first_or_last window_name_or_specification in_line_window_specification opt_lead_or_lag_function +%type <pParseNode> opt_null_treatment opt_from_first_or_last simple_value_specification dynamic_parameter_specification window_name window_clause window_definition_list window_definition +%type <pParseNode> new_window_name existing_window_name window_partition_clause window_partition_column_reference_list window_partition_column_reference window_frame_clause +%type <pParseNode> window_frame_units window_frame_extent window_frame_start window_frame_preceding window_frame_between window_frame_bound_1 window_frame_bound_2 window_frame_bound window_frame_following window_frame_exclusion +%type <pParseNode> opt_window_frame_clause opt_window_partition_clause opt_existing_window_name window_specification opt_window_frame_exclusion opt_window_clause opt_offset +%type <pParseNode> opt_fetch_first_row_count fetch_first_clause offset_row_count fetch_first_row_count first_or_next row_or_rows opt_result_offset_clause result_offset_clause +/* LIMIT and OFFSET */ +%type <pParseNode> opt_limit_offset_clause limit_offset_clause opt_fetch_first_clause +%% + +/* Return Parse Tree to OSQLParser + * (the access over yyval after calling the parser fails, + * + */ +sql_single_statement: + sql + { xxx_pGLOBAL_SQLPARSER->setParseTree( $1 ); } + | sql ';' + { xxx_pGLOBAL_SQLPARSER->setParseTree( $1 ); } + ; + + /* schema definition language */ + /* Note: other ``sql:sal_Unicode() rules appear later in the grammar */ + +sql: + manipulative_statement + | schema_element + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; + +/*** + +op_authorization: + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_AUTHORIZATION user + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +op_schema: + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_NAME + | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($3); + } + ; + +schema: + SQL_TOKEN_CREATE SQL_TOKEN_SCHEMA op_schema op_authorization opt_schema_element_list + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + } + ; + +opt_schema_element_list: + {$$ = SQL_NEW_RULE;} + | schema_glement_list + ; + +schema_element_list: + schema_element + {$$ = SQL_NEW_LISTRULE; + $$->append($1);} + | schema_element_list schema_element + {$1->append($2); + $$ = $1;} + ; +*/ + +schema_element: + base_table_def + | view_def + | privilege_def + | trigger_definition + ; + +base_table_def: + SQL_TOKEN_CREATE SQL_TOKEN_TABLE table_node '(' base_table_element_commalist ')' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation));} + ; + +base_table_element_commalist: + base_table_element + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | base_table_element_commalist ',' base_table_element + {$1->append($3); + $$ = $1;} + ; + +base_table_element: + column_def + | table_constraint_def + ; + +column_def: + column data_type column_def_opt_list + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; + +column_def_opt_list: + /* empty */ {$$ = SQL_NEW_LISTRULE;} + | column_def_opt_list column_def_opt + {$1->append($2); + $$ = $1;} + ; + +nil_fkt: + datetime_value_fct + ; +unique_spec: + SQL_TOKEN_UNIQUE + | SQL_TOKEN_PRIMARY SQL_TOKEN_KEY + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +column_def_opt: + SQL_TOKEN_NOT SQL_TOKEN_NULL + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | unique_spec + | SQL_TOKEN_DEFAULT literal + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | SQL_TOKEN_DEFAULT SQL_TOKEN_NULL + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | SQL_TOKEN_DEFAULT SQL_TOKEN_USER + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | SQL_TOKEN_DEFAULT nil_fkt + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_CHECK + | SQL_TOKEN_CHECK '(' search_condition ')' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation));} + | SQL_TOKEN_REFERENCES table_node + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | SQL_TOKEN_REFERENCES table_node '(' column_commalist ')' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation));} + ; + +table_constraint_def: + unique_spec '(' column_commalist ')' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation));} + | SQL_TOKEN_FOREIGN SQL_TOKEN_KEY '(' column_commalist ')' SQL_TOKEN_REFERENCES table_node + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + $$->append($6); + $$->append($7);} + | SQL_TOKEN_FOREIGN SQL_TOKEN_KEY '(' column_commalist ')' SQL_TOKEN_REFERENCES table_node '(' column_commalist ')' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + $$->append($6); + $$->append($7); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($9); + $$->append(newNode(")", SQLNodeType::Punctuation));} + | SQL_TOKEN_CHECK '(' search_condition ')' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation));} + ; +op_column_commalist: + /* empty */ {$$ = SQL_NEW_RULE;} + | '(' column_commalist ')' + {$$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +column_commalist: + column_commalist ',' column + {$1->append($3); + $$ = $1;} + | column + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + ; + +view_def: + SQL_TOKEN_CREATE SQL_TOKEN_VIEW table_node opt_column_commalist SQL_TOKEN_AS select_statement opt_with_check_option + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); + $$->append($7);} + ; + +opt_with_check_option: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_WITH SQL_TOKEN_CHECK SQL_TOKEN_OPTION + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3);} + ; + +opt_column_commalist: + /* empty */ {$$ = SQL_NEW_RULE;} + | '(' column_commalist ')' + {$$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation));} + ; + +privilege_def: + SQL_TOKEN_GRANT privileges SQL_TOKEN_ON table_node SQL_TOKEN_TO grantee_commalist + opt_with_grant_option + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); + $$->append($7);} + ; + +opt_with_grant_option: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_WITH SQL_TOKEN_GRANT SQL_TOKEN_OPTION + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3);} + ; + +privileges: + SQL_TOKEN_ALL SQL_TOKEN_PRIVILEGES + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | operation_commalist + ; + +operation_commalist: + operation + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | operation_commalist ',' operation + {$1->append($3); + $$ = $1;} + ; + +operation: + SQL_TOKEN_SELECT + | SQL_TOKEN_INSERT opt_column_commalist + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | SQL_TOKEN_DELETE + | SQL_TOKEN_UPDATE opt_column_commalist + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | SQL_TOKEN_REFERENCES opt_column_commalist + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | SQL_TOKEN_USAGE + ; + + +grantee_commalist: + grantee + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | grantee_commalist ',' grantee + {$1->append($3); + $$ = $1;} + ; + +grantee: + SQL_TOKEN_PUBLIC + | user + ; + + /* module language */ + +opt_order_by_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_ORDER SQL_TOKEN_BY ordering_spec_commalist + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3);} + ; + +ordering_spec_commalist: + ordering_spec + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | ordering_spec_commalist ',' ordering_spec + {$1->append($3); + $$ = $1;} + ; + +ordering_spec: +/* SQL_TOKEN_INTNUM opt_asc_desc + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} +*/ + predicate opt_asc_desc + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + + | row_value_constructor_elem opt_asc_desc + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + ; + +opt_asc_desc: + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_ASC + | SQL_TOKEN_DESC + ; + + +/*** +manipulative_statement_list: + manipulative_statement + {$$ = SQL_NEW_LISTRULE; + $$->append($1);} + | manipulative_statement_list manipulative_statement + {$1->append($2); + $$ = $1;} + ; +***/ + +sql_not: +/* vide */ + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_NOT + ; + +/* manipulative statements */ + +manipulative_statement: + commit_statement +/* | delete_statement_positioned*/ + | delete_statement_searched + | fetch_statement + | insert_statement + | rollback_statement + | select_statement_into +/* | update_statement_positioned*/ + | update_statement_searched + | union_statement + | '{' odbc_call_spec '}' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("{", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode("}", SQLNodeType::Punctuation)); + } + ; + +union_statement: + select_statement + | union_statement SQL_TOKEN_UNION all select_statement + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +commit_statement: + SQL_TOKEN_COMMIT SQL_TOKEN_WORK + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + ; +/* +delete_statement_positioned: + SQL_TOKEN_DELETE SQL_TOKEN_FROM table_node SQL_TOKEN_WHERE SQL_TOKEN_CURRENT SQL_TOKEN_OF cursor + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); + $$->append($7);} + ; +*/ +delete_statement_searched: + SQL_TOKEN_DELETE SQL_TOKEN_FROM table_node opt_where_clause + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4);} + ; + +fetch_statement: + SQL_TOKEN_FETCH cursor SQL_TOKEN_INTO target_commalist + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4);} + ; + +insert_statement: + SQL_TOKEN_INSERT SQL_TOKEN_INTO table_node opt_column_commalist query_exp + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5);} + ; +values_or_query_spec: + SQL_TOKEN_VALUES '(' table_value_const_list ')' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; + +table_value_const_list: + row_value_constructor + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | table_value_const_list ',' row_value_constructor + {$1->append($3); + $$ = $1;} + ; +/* +row_value_const_list: + row_value_constructor_elem + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | row_value_const_list ',' row_value_constructor_elem + {$1->append($3); + $$ = $1;} + ; +*/ +row_value_constructor: + row_value_constructor_elem +/* | '(' row_value_const_list ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + */ + ; +row_value_constructor_elem: + value_exp /*[^')']*/ + | SQL_TOKEN_DEFAULT + ; + + +rollback_statement: + SQL_TOKEN_ROLLBACK SQL_TOKEN_WORK + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + ; + + + /* INTO target_commalist herausgenommen */ +select_statement_into: + SQL_TOKEN_SELECT opt_all_distinct selection SQL_TOKEN_INTO target_commalist table_exp + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); } + ; + +opt_all_distinct: + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_ALL + | SQL_TOKEN_DISTINCT + + ; +/* +update_statement_positioned: + SQL_TOKEN_UPDATE table_node SQL_TOKEN_SET assignment_commalist + SQL_TOKEN_WHERE SQL_TOKEN_CURRENT SQL_TOKEN_OF cursor + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); + $$->append($7); + $$->append($8);} + ; +*/ +assignment_commalist: + assignment + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | assignment_commalist ',' assignment + {$1->append($3); + $$ = $1;} + ; + +assignment: + column SQL_EQUAL update_source + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3);} + ; +update_source: + value_exp + | SQL_TOKEN_DEFAULT + ; +update_statement_searched: + SQL_TOKEN_UPDATE table_node SQL_TOKEN_SET assignment_commalist opt_where_clause + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5);} + ; + +target_commalist: + target + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | target_commalist ',' target + {$1->append($3); + $$ = $1;} + ; + +target: + parameter_ref + ; + +opt_where_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | where_clause + ; + + /* query expressions */ + +query_term: + non_join_query_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +/* SELECT STATEMENT */ +select_statement: + SQL_TOKEN_SELECT opt_all_distinct selection table_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; + +selection: + '*' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("*", SQLNodeType::Punctuation)); + } + | scalar_exp_commalist + ; +opt_result_offset_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | result_offset_clause + ; +result_offset_clause: + SQL_TOKEN_OFFSET offset_row_count row_or_rows + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +opt_fetch_first_row_count: + /* empty */ {$$ = SQL_NEW_RULE;} + | fetch_first_row_count + ; +first_or_next: + SQL_TOKEN_FIRST + | SQL_TOKEN_NEXT + ; +row_or_rows: + SQL_TOKEN_ROW + | SQL_TOKEN_ROWS + ; +opt_fetch_first_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | fetch_first_clause + ; +fetch_first_clause: + SQL_TOKEN_FETCH first_or_next opt_fetch_first_row_count row_or_rows SQL_TOKEN_ONLY + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + } + ; +offset_row_count: + literal + ; +fetch_first_row_count: + literal + ; + +opt_limit_offset_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | limit_offset_clause + ; +opt_offset: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_OFFSET SQL_TOKEN_INTNUM + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +limit_offset_clause: + SQL_TOKEN_LIMIT SQL_TOKEN_INTNUM opt_offset + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +table_exp: + from_clause opt_where_clause opt_group_by_clause opt_having_clause opt_window_clause opt_order_by_clause opt_limit_offset_clause opt_result_offset_clause opt_fetch_first_clause + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); + $$->append($7); + $$->append($8); + $$->append($9); + } + ; + +from_clause: + SQL_TOKEN_FROM table_ref_commalist + { $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); } + ; + +table_ref_commalist: + + table_ref + { $$ = SQL_NEW_COMMALISTRULE; + $$->append($1); } + | table_ref_commalist ',' table_ref + { $1->append($3); + $$ = $1; } + ; + +opt_as: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_AS + ; +opt_row: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_ROW + ; +table_primary_as_range_column: + {$$ = SQL_NEW_RULE;} + | opt_as SQL_TOKEN_NAME op_column_commalist + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +table_ref: + table_node table_primary_as_range_column + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | subquery range_variable op_column_commalist + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | joined_table + | '{' SQL_TOKEN_OJ joined_table '}' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("{", SQLNodeType::Punctuation)); + $$->append($2); + $$->append($3); + $$->append(newNode("}", SQLNodeType::Punctuation)); + } + | '(' joined_table ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +where_clause: + SQL_TOKEN_WHERE search_condition + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + ; + +opt_group_by_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_GROUP SQL_TOKEN_BY column_ref_commalist + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3);} + ; + +column_ref_commalist: + column_ref + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | set_fct_spec + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | column_ref_commalist ',' column_ref + {$1->append($3); + $$ = $1;} + | column_ref_commalist ',' set_fct_spec + {$1->append($3); + $$ = $1;} + ; + +opt_having_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_HAVING search_condition + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + ; + + /* search conditions */ +boolean_primary: + predicate + | '(' search_condition ')' + { // boolean_primary: rule 2 + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | row_value_constructor_elem /*[^')' ',']*/ + { + if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck())// boolean_primary: rule 3 + { + $$ = SQL_NEW_RULE; + sal_Int16 nErg = 0; + if ( SQL_ISTOKEN( $1, NULL)) + { + OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref)); + pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name)); + OSQLParseNode* pTFN = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::test_for_null)); + pTFN->append(pColumnRef); + + OSQLParseNode* pNPP2 = new OSQLInternalNode("", SQLNodeType::Rule, OSQLParser::RuleID(OSQLParseNode::null_predicate_part_2)); + pNPP2->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_IS)); + pNPP2->append(new OSQLInternalNode("", SQLNodeType::Rule, OSQLParser::RuleID(OSQLParseNode::sql_not))); + pNPP2->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_NULL)); + pTFN->append(pNPP2); + + $$->append(pTFN); + + nErg = 1; + } + else + { + nErg = xxx_pGLOBAL_SQLPARSER->buildComparisonRule($$,$1); + } + if(nErg == 1) + { + OSQLParseNode* pTemp = $$; + $$ = pTemp->removeAt((sal_uInt32)0); + delete pTemp; + } + else + { + delete $$; + if(nErg) + YYERROR; + else + YYABORT; + } + } + else + YYERROR; + } + ; +parenthesized_boolean_value_expression: + '(' search_condition ')' + { // boolean_primary: rule 2 + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +boolean_factor: + boolean_primary %dprec 2 + | SQL_TOKEN_NOT boolean_primary %dprec 1 + { // boolean_factor: rule 1 + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +boolean_term: + boolean_factor + | boolean_term SQL_TOKEN_AND boolean_factor + { + $$ = SQL_NEW_RULE; // boolean_term: rule 1 + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +search_condition: + boolean_term + | search_condition SQL_TOKEN_OR boolean_term + { + $$ = SQL_NEW_RULE; // search_condition + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +predicate: + comparison_predicate %dprec 1 + | between_predicate + | all_or_any_predicate + | existence_test + | unique_test + | test_for_null %dprec 2 + | in_predicate + | like_predicate + ; +comparison_predicate_part_2: + comparison row_value_constructor + { + $$ = SQL_NEW_RULE; // comparison_predicate: rule 1 + $$->append($1); + $$->append($2); + } +comparison_predicate: + row_value_constructor comparison row_value_constructor + { + $$ = SQL_NEW_RULE; // comparison_predicate: rule 1 + $$->append($1); + $$->append($2); + $$->append($3); + } + | comparison row_value_constructor + { + if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // comparison_predicate: rule 2 + { + $$ = SQL_NEW_RULE; + sal_Int16 nErg = xxx_pGLOBAL_SQLPARSER->buildPredicateRule($$,$2,$1); + if(nErg == 1) + { + OSQLParseNode* pTemp = $$; + $$ = pTemp->removeAt((sal_uInt32)0); + delete pTemp; + } + else + { + delete $$; + YYABORT; + } + } + else + { + YYERROR; + } + } + ; +comparison: + SQL_LESS + | SQL_NOTEQUAL + | SQL_EQUAL + | SQL_GREAT + | SQL_LESSEQ + | SQL_GREATEQ + | SQL_TOKEN_IS sql_not SQL_TOKEN_DISTINCT SQL_TOKEN_FROM + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_IS sql_not + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +between_predicate_part_2: + sql_not SQL_TOKEN_BETWEEN row_value_constructor SQL_TOKEN_AND row_value_constructor + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // between_predicate: rule 2 + { + $$ = SQL_NEW_RULE; + + sal_Int16 nErg = xxx_pGLOBAL_SQLPARSER->buildPredicateRule($$,$3,$2,$5); + if(nErg == 1) + { + OSQLParseNode* pTemp = $$; + $$ = pTemp->removeAt((sal_uInt32)0); + OSQLParseNode* pColumnRef = $$->removeAt((sal_uInt32)0); + $$->insert(0,$1); + OSQLParseNode* pBetween_predicate = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::between_predicate)); + pBetween_predicate->append(pColumnRef); + pBetween_predicate->append($$); + $$ = pBetween_predicate; + + delete pTemp; + delete $4; + } + else + { + delete $$; + YYABORT; + } + } + else + { + $$ = SQL_NEW_RULE; // between_predicate: rule 1 + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + } + } +between_predicate: + row_value_constructor between_predicate_part_2 + { + $$ = SQL_NEW_RULE; // between_predicate: rule 1 + $$->append($1); + $$->append($2); + } + | between_predicate_part_2 + ; +character_like_predicate_part_2: + sql_not SQL_TOKEN_LIKE string_value_exp opt_escape + { + $$ = SQL_NEW_RULE; // like_predicate: rule 1 + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +other_like_predicate_part_2: + sql_not SQL_TOKEN_LIKE value_exp_primary opt_escape + { + $$ = SQL_NEW_RULE; // like_predicate: rule 1 + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +like_predicate: + row_value_constructor character_like_predicate_part_2 + { + $$ = SQL_NEW_RULE; // like_predicate: rule 1 + $$->append($1); + $$->append($2); + } + | row_value_constructor other_like_predicate_part_2 + { + $$ = SQL_NEW_RULE; // like_predicate: rule 3 + $$->append($1); + $$->append($2); + } + | character_like_predicate_part_2 + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // like_predicate: rule 5 + { + OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref)); + pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name)); + + $$ = SQL_NEW_RULE; + $$->append(pColumnRef); + $$->append($1); + OSQLParseNode* p2nd = $1->removeAt(2); + OSQLParseNode* p3rd = $1->removeAt(2); + if ( !xxx_pGLOBAL_SQLPARSER->buildLikeRule($1,p2nd,p3rd) ) + { + delete $$; + YYABORT; + } + $1->append(p3rd); + } + else + YYERROR; + } + | other_like_predicate_part_2 + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // like_predicate: rule 6 + { + OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref)); + pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name)); + + $$ = SQL_NEW_RULE; + $$->append(pColumnRef); + $$->append($1); + OSQLParseNode* p2nd = $1->removeAt(2); + OSQLParseNode* p3rd = $1->removeAt(2); + if ( !xxx_pGLOBAL_SQLPARSER->buildLikeRule($1,p2nd,p3rd) ) + { + delete $$; + YYABORT; + } + $1->append(p3rd); + } + else + YYERROR; + } + ; + +opt_escape: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_ESCAPE string_value_exp + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + | '{' SQL_TOKEN_ESCAPE SQL_TOKEN_STRING '}' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("{", SQLNodeType::Punctuation)); + $$->append($2); + $$->append($3); + $$->append(newNode("}", SQLNodeType::Punctuation)); + } + ; + +null_predicate_part_2: + SQL_TOKEN_IS sql_not SQL_TOKEN_NULL + { + $$ = SQL_NEW_RULE; // test_for_null: rule 1 + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_IS sql_not SQL_TOKEN_UNKNOWN + { + $$ = SQL_NEW_RULE; // test_for_null: rule 1 + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +test_for_null: + row_value_constructor null_predicate_part_2 + { + $$ = SQL_NEW_RULE; // test_for_null: rule 1 + $$->append($1); + $$->append($2); + } + | null_predicate_part_2 + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck())// test_for_null: rule 2 + { + OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref)); + pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name)); + + $$ = SQL_NEW_RULE; + $$->append(pColumnRef); + $$->append($1); + } + else + YYERROR; + } + ; +in_predicate_value: + subquery + {$$ = SQL_NEW_RULE; + $$->append($1); + } + | '(' value_exp_commalist ')' + {$$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +in_predicate_part_2: + sql_not SQL_TOKEN_IN in_predicate_value + { + $$ = SQL_NEW_RULE;// in_predicate: rule 1 + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +in_predicate: + row_value_constructor in_predicate_part_2 + { + $$ = SQL_NEW_RULE;// in_predicate: rule 1 + $$->append($1); + $$->append($2); + } + | in_predicate_part_2 + { + if ( xxx_pGLOBAL_SQLPARSER->inPredicateCheck() )// in_predicate: rule 2 + { + OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref)); + pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name)); + + $$ = SQL_NEW_RULE; + $$->append(pColumnRef); + $$->append($1); + } + else + YYERROR; + } + ; +quantified_comparison_predicate_part_2: + comparison any_all_some subquery + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +all_or_any_predicate: + row_value_constructor quantified_comparison_predicate_part_2 + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | quantified_comparison_predicate_part_2 + { + if(xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) + { + OSQLParseNode* pColumnRef = newNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref)); + pColumnRef->append(newNode(xxx_pGLOBAL_SQLPARSER->getFieldName(),SQLNodeType::Name)); + + $$ = SQL_NEW_RULE; + $$->append(pColumnRef); + $$->append($1); + } + else + YYERROR; + } + ; + +any_all_some: + SQL_TOKEN_ANY + | SQL_TOKEN_ALL + | SQL_TOKEN_SOME + ; + +existence_test: + SQL_TOKEN_EXISTS subquery + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + ; +unique_test: + SQL_TOKEN_UNIQUE subquery + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2);} + ; +subquery: + '(' query_exp ')' + {$$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation));} + ; + + /* scalar expressions */ +scalar_exp_commalist: + select_sublist + { + $$ = SQL_NEW_COMMALISTRULE; + $$->append($1); + } + | scalar_exp_commalist ',' select_sublist + { + $1->append($3); + $$ = $1; + } + ; +select_sublist: +/* table_node '.' '*' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append(newNode("*", SQLNodeType::Punctuation)); + } +*/ + derived_column + + ; + +parameter_ref: + parameter + ; + +/* +op_like: + '*' + { + $$ = newNode("*", SQLNodeType::Punctuation); + } + | '?' + { + $$ = newNode("?", SQLNodeType::Punctuation); + } + | op_like '*' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("*", SQLNodeType::Punctuation)); + xxx_pGLOBAL_SQLPARSER->reduceLiteral($$, sal_False); + } + | op_like '?' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("?", SQLNodeType::Punctuation)); + xxx_pGLOBAL_SQLPARSER->reduceLiteral($$, sal_False); + } + ; +*/ + +literal: +/* SQL_TOKEN_STRING + | */SQL_TOKEN_INT + | SQL_TOKEN_REAL_NUM + | SQL_TOKEN_INTNUM + | SQL_TOKEN_APPROXNUM + | SQL_TOKEN_ACCESS_DATE +/* rules for predicate check */ + | literal SQL_TOKEN_STRING + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + OSQLParser::reduceLiteral($$, true); + } + else + YYERROR; + } + | literal SQL_TOKEN_INT + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + OSQLParser::reduceLiteral($$, true); + } + else + YYERROR; + } + | literal SQL_TOKEN_REAL_NUM + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + OSQLParser::reduceLiteral($$, true); + } + else + YYERROR; + } + | literal SQL_TOKEN_APPROXNUM + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + OSQLParser::reduceLiteral($$, true); + } + else + YYERROR; + } + ; + + /* miscellaneous */ +as_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_AS column + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | column + ; +position_exp: + SQL_TOKEN_POSITION '(' value_exp SQL_TOKEN_IN value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_POSITION '(' value_exp_commalist ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +num_value_fct: + position_exp + | extract_exp + | length_exp + ; +char_length_exp: + SQL_TOKEN_CHAR_LENGTH '(' value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_SQL_TOKEN_INTNUM '(' value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + + ; +octet_length_exp: + SQL_TOKEN_OCTET_LENGTH '(' value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +bit_length_exp: + SQL_TOKEN_BIT_LENGTH '(' value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +length_exp: + char_length_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | octet_length_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | bit_length_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +datetime_field: + non_second_datetime_field + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | SQL_TOKEN_SECOND + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +extract_field: + time_zone_field + | datetime_field + | value_exp + ; +time_zone_field: + SQL_TOKEN_TIMEZONE_HOUR + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | SQL_TOKEN_TIMEZONE_MINUTE + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +extract_exp: + SQL_TOKEN_EXTRACT '(' extract_field SQL_TOKEN_FROM value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +unsigned_value_spec: + general_value_spec + | literal + ; +general_value_spec: + parameter + | SQL_TOKEN_USER + | SQL_TOKEN_NULL + | SQL_TOKEN_FALSE + | SQL_TOKEN_TRUE + | SQL_TOKEN_VALUE + | SQL_TOKEN_CURRENT_CATALOG + | SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP + | SQL_TOKEN_CURRENT_PATH + | SQL_TOKEN_CURRENT_ROLE + | SQL_TOKEN_CURRENT_SCHEMA + | SQL_TOKEN_CURRENT_USER + | SQL_TOKEN_SESSION_USER + | SQL_TOKEN_SYSTEM_USER + ; +set_fct_spec: + general_set_fct + | '{' odbc_fct_spec '}' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("{", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode("}", SQLNodeType::Punctuation)); + } + | function_name '(' ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | function_name0 '(' ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | function_name1 '(' function_arg ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | function_name2 '(' function_arg_commalist2 ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | function_name3 '(' function_arg_commalist3 ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | string_function_4Argument '(' function_arg_commalist4 ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | function_name '(' function_args_commalist ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | function_name12 '(' function_args_commalist ')' + { + if ( $3->count() == 1 || $3->count() == 2 ) + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + else + YYERROR; + } + | function_name23 '(' function_args_commalist ')' + { + if ( $3->count() == 2 || $3->count() == 3) + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + else + YYERROR; + } + ; +function_name0: + date_function_0Argument + | numeric_function_0Argument + ; +function_name1: + string_function_1Argument + | date_function_1Argument + | numeric_function_1Argument + ; +function_name2: + string_function_2Argument + | numeric_function_2Argument + ; +function_name12: + SQL_TOKEN_ROUND + | SQL_TOKEN_WEEK + | SQL_TOKEN_LOGF + | SQL_TOKEN_LOG + ; +function_name23: + SQL_TOKEN_LOCATE + | SQL_TOKEN_DATEDIFF + ; +function_name3: + string_function_3Argument + ; +function_name: + string_function + | date_function + | numeric_function + | SQL_TOKEN_NAME + ; +string_function_1Argument: + SQL_TOKEN_LENGTH + | SQL_TOKEN_ASCII + | SQL_TOKEN_LCASE + | SQL_TOKEN_LTRIM + | SQL_TOKEN_RTRIM + | SQL_TOKEN_SPACE + | SQL_TOKEN_UCASE + ; + +string_function_2Argument: + SQL_TOKEN_REPEAT + | SQL_TOKEN_LEFT + | SQL_TOKEN_RIGHT + ; +string_function_3Argument: + SQL_TOKEN_REPLACE + ; +string_function_4Argument: + SQL_TOKEN_INSERT + ; + +string_function: + SQL_TOKEN_CHAR + | SQL_TOKEN_CONCAT + | SQL_TOKEN_DIFFERENCE + | SQL_TOKEN_LOCATE_2 + | SQL_TOKEN_SOUNDEX + ; +date_function_0Argument: + SQL_TOKEN_CURDATE + | SQL_TOKEN_CURTIME + | SQL_TOKEN_NOW + ; +date_function_1Argument: + SQL_TOKEN_DAYOFWEEK + | SQL_TOKEN_DAYOFMONTH + | SQL_TOKEN_DAYOFYEAR + | SQL_TOKEN_MONTH + | SQL_TOKEN_DAYNAME + | SQL_TOKEN_MONTHNAME + | SQL_TOKEN_QUARTER + | SQL_TOKEN_HOUR + | SQL_TOKEN_MINUTE + | SQL_TOKEN_SECOND + | SQL_TOKEN_YEAR + | SQL_TOKEN_DAY + | SQL_TOKEN_TIMEVALUE + | SQL_TOKEN_DATEVALUE + ; + +date_function: + SQL_TOKEN_TIMESTAMPADD + | SQL_TOKEN_TIMESTAMPDIFF + ; +numeric_function_0Argument: + SQL_TOKEN_PI + ; +numeric_function_1Argument: + SQL_TOKEN_ABS + | SQL_TOKEN_ACOS + | SQL_TOKEN_ASIN + | SQL_TOKEN_ATAN + | SQL_TOKEN_CEILING + | SQL_TOKEN_COS + | SQL_TOKEN_COT + | SQL_TOKEN_DEGREES + | SQL_TOKEN_FLOOR + | SQL_TOKEN_SIGN + | SQL_TOKEN_SIN + | SQL_TOKEN_SQRT + | SQL_TOKEN_TAN + | SQL_TOKEN_EXP + | SQL_TOKEN_LOG10 + | SQL_TOKEN_LN + | SQL_TOKEN_RADIANS + | SQL_TOKEN_ROUNDMAGIC + ; +numeric_function_2Argument: + SQL_TOKEN_ATAN2 + | SQL_TOKEN_MOD + | SQL_TOKEN_POWER + ; +numeric_function: + SQL_TOKEN_RAND + | SQL_TOKEN_TRUNCATE + ; + +window_function: + window_function_type SQL_TOKEN_OVER window_name_or_specification + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +window_function_type : + rank_function_type '(' ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_ROW_NUMBER '(' ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | general_set_fct + | ntile_function + | lead_or_lag_function + | first_or_last_value_function + | nth_value_function +; +ntile_function : + SQL_TOKEN_NTILE '(' number_of_tiles ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +dynamic_parameter_specification: + parameter + ; +simple_value_specification: + literal + ; +number_of_tiles : + simple_value_specification + | dynamic_parameter_specification + ; +opt_lead_or_lag_function: + /* empty */ {$$ = SQL_NEW_RULE;} + | ',' offset + { + $$ = SQL_NEW_RULE; + $$->append(newNode(",", SQLNodeType::Punctuation)); + $$->append($2); + } + | ',' offset ',' default_expression + { + $$ = SQL_NEW_RULE; + $$->append(newNode(",", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(",", SQLNodeType::Punctuation)); + $$->append($4); + } + ; +opt_null_treatment: + /* empty */ {$$ = SQL_NEW_RULE;} + | null_treatment + ; + +lead_or_lag_function: + lead_or_lag '(' lead_or_lag_extent opt_lead_or_lag_function ')' opt_null_treatment + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + $$->append($6); + } + ; +lead_or_lag: + SQL_TOKEN_LEAD + | SQL_TOKEN_LAG + ; +lead_or_lag_extent: + value_exp + ; +offset: + SQL_TOKEN_INTNUM + ; +default_expression: + value_exp + ; +null_treatment: + SQL_TOKEN_RESPECT SQL_TOKEN_NULLS + | SQL_TOKEN_IGNORE SQL_TOKEN_NULLS + ; +first_or_last_value_function: + first_or_last_value '(' value_exp ')' opt_null_treatment + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + $$->append($5); + } + ; +first_or_last_value : + SQL_TOKEN_FIRST_VALUE + | SQL_TOKEN_LAST_VALUE + ; +opt_from_first_or_last: + /* empty */ {$$ = SQL_NEW_RULE;} + | from_first_or_last + ; +nth_value_function: + SQL_TOKEN_NTH_VALUE '(' value_exp ',' nth_row ')' opt_from_first_or_last opt_null_treatment + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(",", SQLNodeType::Punctuation)); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + $$->append($7); + $$->append($8); + } + ; +nth_row: + simple_value_specification + | dynamic_parameter_specification + ; +from_first_or_last: + SQL_TOKEN_FROM SQL_TOKEN_FIRST + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_FROM SQL_TOKEN_LAST + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +window_name: + SQL_TOKEN_NAME + ; +window_name_or_specification: + window_name + | in_line_window_specification + ; +in_line_window_specification: + window_specification + ; +opt_window_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | window_clause + ; +window_clause: + SQL_TOKEN_WINDOW window_definition_list + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +window_definition_list: + window_definition_list ',' window_definition + {$1->append($3); + $$ = $1;} + | window_definition + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + ; +window_definition: + new_window_name SQL_TOKEN_AS window_specification + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +new_window_name: + window_name + ; +window_specification: + '(' + opt_existing_window_name + opt_window_partition_clause + opt_order_by_clause + opt_window_frame_clause + ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +opt_existing_window_name: + /* empty */ {$$ = SQL_NEW_RULE;} + | existing_window_name + ; +opt_window_partition_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | window_partition_clause + ; +opt_window_frame_clause: + /* empty */ {$$ = SQL_NEW_RULE;} + | window_frame_clause + ; +existing_window_name: + window_name + ; +window_partition_clause: + SQL_TOKEN_PARTITION SQL_TOKEN_BY window_partition_column_reference_list + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +window_partition_column_reference_list: + window_partition_column_reference_list ',' window_partition_column_reference + {$1->append($3); + $$ = $1;} + | window_partition_column_reference + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + ; +window_partition_column_reference: + column_ref opt_collate_clause + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +opt_window_frame_exclusion: + /* empty */ {$$ = SQL_NEW_RULE;} + | window_frame_exclusion + ; +window_frame_clause: + window_frame_units window_frame_extent opt_window_frame_exclusion + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +window_frame_units: + SQL_TOKEN_ROWS + | SQL_TOKEN_RANGE + ; +window_frame_extent: + window_frame_start + | window_frame_between + ; +window_frame_start: + SQL_TOKEN_UNBOUNDED SQL_TOKEN_PRECEDING + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | window_frame_preceding + | SQL_TOKEN_CURRENT SQL_TOKEN_ROW + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +window_frame_preceding: + unsigned_value_spec SQL_TOKEN_PRECEDING + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +window_frame_between: + SQL_TOKEN_BETWEEN window_frame_bound_1 SQL_TOKEN_AND window_frame_bound_2 + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +window_frame_bound_1: + window_frame_bound + ; +window_frame_bound_2: + window_frame_bound + ; +window_frame_bound: + window_frame_start + | SQL_TOKEN_UNBOUNDED SQL_TOKEN_FOLLOWING + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | window_frame_following + ; +window_frame_following: + unsigned_value_spec SQL_TOKEN_FOLLOWING + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +window_frame_exclusion: + SQL_TOKEN_EXCLUDE SQL_TOKEN_CURRENT SQL_TOKEN_ROW + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_EXCLUDE SQL_TOKEN_GROUP + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_EXCLUDE SQL_TOKEN_TIES + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_EXCLUDE SQL_TOKEN_NO SQL_TOKEN_OTHERS + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +op_parameter: + {$$ = SQL_NEW_RULE;} + | '?' SQL_EQUAL + { + $$ = SQL_NEW_RULE; + $$->append(newNode("?", SQLNodeType::Punctuation)); + $$->append($2); + } + ; +odbc_call_spec: + op_parameter SQL_TOKEN_CALL table_node op_odbc_call_parameter + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; + +op_odbc_call_parameter: + {$$ = SQL_NEW_RULE;} + | '(' odbc_parameter_commalist ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; + +odbc_parameter_commalist: + odbc_parameter + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | odbc_parameter_commalist ',' odbc_parameter + { + $1->append($3); + $$ = $1; + } + ; +odbc_parameter: + /* empty */ {$$ = SQL_NEW_RULE;} + | literal + | parameter + ; + +odbc_fct_spec: + odbc_fct_type SQL_TOKEN_STRING + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_FN set_fct_spec + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; + +odbc_fct_type: + SQL_TOKEN_D + | SQL_TOKEN_T + | SQL_TOKEN_TS + ; + +general_set_fct: + set_fct_type '(' opt_all_distinct function_arg ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_COUNT '(' '*' ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append(newNode("*", SQLNodeType::Punctuation)); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_COUNT '(' opt_all_distinct function_arg ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | ordered_set_function + | array_aggregate_function + ; +set_fct_type: + SQL_TOKEN_AVG + | SQL_TOKEN_MAX + | SQL_TOKEN_MIN + | SQL_TOKEN_SUM + | SQL_TOKEN_EVERY + | SQL_TOKEN_ANY + | SQL_TOKEN_SOME + | SQL_TOKEN_STDDEV_POP + | SQL_TOKEN_STDDEV_SAMP + | SQL_TOKEN_VAR_SAMP + | SQL_TOKEN_VAR_POP + | SQL_TOKEN_COLLECT + | SQL_TOKEN_FUSION + | SQL_TOKEN_INTERSECTION + ; + +ordered_set_function: + hypothetical_set_function + | inverse_distribution_function + ; +hypothetical_set_function: + rank_function_type '(' hypothetical_set_function_value_expression_list ')' within_group_specification + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + $$->append($5); + } + | rank_function_type '(' hypothetical_set_function_value_expression_list SQL_TOKEN_BY value_exp_commalist ')' within_group_specification + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + $$->append($7); + } + ; + +within_group_specification: + { + $$ = SQL_NEW_RULE; + } + | SQL_TOKEN_WITHIN SQL_TOKEN_GROUP '(' opt_order_by_clause ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +hypothetical_set_function_value_expression_list: + value_exp_commalist + ; + +inverse_distribution_function: + inverse_distribution_function_type '('inverse_distribution_function_argument ')' within_group_specification + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +inverse_distribution_function_argument: + num_value_exp + ; +inverse_distribution_function_type: + SQL_TOKEN_PERCENTILE_CONT + | SQL_TOKEN_PERCENTILE_DISC + ; + +array_aggregate_function: + SQL_TOKEN_ARRAY_AGG '(' value_exp opt_order_by_clause ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; + +rank_function_type: + SQL_TOKEN_RANK + | SQL_TOKEN_DENSE_RANK + | SQL_TOKEN_PERCENT_RANK + | SQL_TOKEN_CUME_DIST + ; +outer_join_type: + SQL_TOKEN_LEFT %prec SQL_TOKEN_LEFT + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | SQL_TOKEN_RIGHT %prec SQL_TOKEN_RIGHT + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | SQL_TOKEN_FULL %prec SQL_TOKEN_FULL + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +join_condition: + SQL_TOKEN_ON search_condition + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +join_spec: + join_condition + | named_columns_join + ; +join_type: + /* empty */ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_INNER + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | outer_join_type + | outer_join_type SQL_TOKEN_OUTER + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +cross_union: + table_ref SQL_TOKEN_CROSS SQL_TOKEN_JOIN table_ref + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; + +qualified_join: + /* when SQL_TOKEN_NATURAL, then no join_spec */ + table_ref SQL_TOKEN_NATURAL join_type SQL_TOKEN_JOIN table_ref + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + } + | table_ref join_type SQL_TOKEN_JOIN table_ref join_spec + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + } + | cross_union + ; +joined_table: + qualified_join + ; +named_columns_join: + SQL_TOKEN_USING '(' column_commalist ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +simple_table: + select_statement + | values_or_query_spec + ; + +non_join_query_primary: + simple_table + | '(' non_join_query_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +non_join_query_term: + non_join_query_primary + | query_term SQL_TOKEN_INTERSECT all query_primary + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +query_primary: + non_join_query_primary + ; +non_join_query_exp: + non_join_query_term + | query_exp SQL_TOKEN_UNION all query_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | query_exp SQL_TOKEN_EXCEPT all query_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +all: + /* empty*/ {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_ALL + ; +query_exp: + non_join_query_exp /*[^')']*/ + ; +scalar_subquery: + subquery + ; +cast_operand: + value_exp + ; +cast_target: + table_node + | data_type + ; +cast_spec: + SQL_TOKEN_CAST '(' cast_operand SQL_TOKEN_AS cast_target ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +value_exp_primary: + unsigned_value_spec + | column_ref + | set_fct_spec + | scalar_subquery + | case_expression + | window_function + | '(' value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | cast_spec + ; + +num_primary: + value_exp_primary + | num_value_fct + ; +factor: + num_primary + | '-' num_primary %prec SQL_TOKEN_UMINUS + { + $$ = SQL_NEW_RULE; + $$->append(newNode("-", SQLNodeType::Punctuation)); + $$->append($2); + } + | '+' num_primary %prec SQL_TOKEN_UMINUS + { + $$ = SQL_NEW_RULE; + $$->append(newNode("+", SQLNodeType::Punctuation)); + $$->append($2); + } + ; + +term: + factor + | term '*' factor + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("*", SQLNodeType::Punctuation)); + $$->append($3); + } + | term '/' factor + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("/", SQLNodeType::Punctuation)); + $$->append($3); + } + ; + +num_value_exp: + term + | num_value_exp '+' term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("+", SQLNodeType::Punctuation)); + $$->append($3); + } + | num_value_exp '-' term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("-", SQLNodeType::Punctuation)); + $$->append($3); + } + ; +datetime_primary: +/* value_exp_primary + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + |*/ datetime_value_fct + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +datetime_value_fct: + SQL_TOKEN_CURRENT_DATE + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | SQL_TOKEN_CURRENT_TIME + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | SQL_TOKEN_CURRENT_TIMESTAMP + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +time_zone: + SQL_TOKEN_AT time_zone_specifier + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +time_zone_specifier: + SQL_TOKEN_LOCAL + { + $$ = SQL_NEW_RULE; + $$->append($1); + } +/* | SQL_TOKEN_TIME SQL_TOKEN_ZONE interval_value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + }*/ + ; +datetime_factor: + datetime_primary + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | datetime_primary time_zone + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +datetime_term: + datetime_factor + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +/* +interval_term: + literal + | interval_term '*' factor + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("*", SQLNodeType::Punctuation)); + $$->append($3); + } + | interval_term '/' factor + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("/", SQLNodeType::Punctuation)); + $$->append($3); + } + ; +*/ +datetime_value_exp: + datetime_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + } +/* | interval_value_exp '+' datetime_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("+", SQLNodeType::Punctuation)); + $$->append($3); + } + | datetime_value_exp '+' interval_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("+", SQLNodeType::Punctuation)); + $$->append($3); + } + | datetime_value_exp '-' interval_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("-", SQLNodeType::Punctuation)); + $$->append($3); + } +*/ ; +/* +interval_value_exp: + interval_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | interval_value_exp '+' interval_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("+", SQLNodeType::Punctuation)); + $$->append($3); + } + | interval_value_exp '-' interval_term + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("-", SQLNodeType::Punctuation)); + $$->append($3); + } + | '(' datetime_value_exp '-' datetime_term ')' interval_qualifier + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode("-", SQLNodeType::Punctuation)); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + $$->append($6); + } + ; +*/ +non_second_datetime_field: + SQL_TOKEN_YEAR + | SQL_TOKEN_MONTH + | SQL_TOKEN_DAY + | SQL_TOKEN_HOUR + | SQL_TOKEN_MINUTE + ; +start_field: + non_second_datetime_field opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +end_field: + non_second_datetime_field + | SQL_TOKEN_SECOND opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; + +single_datetime_field: + non_second_datetime_field opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_SECOND opt_paren_precision_scale + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; + +interval_qualifier: + start_field SQL_TOKEN_TO end_field + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | single_datetime_field + ; + +function_arg_commalist2: + function_arg ',' function_arg + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1); + $$->append($3);} + ; +function_arg_commalist3: + function_arg ',' function_arg ',' function_arg + { + $$ = SQL_NEW_COMMALISTRULE; + $$->append($1); + $$->append($3); + $$->append($5); + } + ; +function_arg_commalist4: + function_arg ',' function_arg ',' function_arg ',' function_arg + { + $$ = SQL_NEW_COMMALISTRULE; + $$->append($1); + $$->append($3); + $$->append($5); + $$->append($7); + } + ; +value_exp_commalist: + value_exp + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | value_exp_commalist ',' value_exp + {$1->append($3); + $$ = $1;} + /* this rule is only valid if we check predicates */ + | value_exp_commalist ';' value_exp + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) + { + $1->append($3); + $$ = $1; + } + else + YYERROR; + } + ; +function_arg: + result + | value_exp comparison value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | value_exp SQL_TOKEN_USING value_exp comparison value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | value_exp SQL_TOKEN_BY value_exp_commalist + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +function_args_commalist: + function_arg + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | function_args_commalist ',' function_arg + {$1->append($3); + $$ = $1;} + /* this rule is only valid if we check predicates */ + | function_args_commalist ';' function_arg + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) + { + $1->append($3); + $$ = $1; + } + else + YYERROR; + } + ; + +value_exp: + num_value_exp /*[^')']*/ + | string_value_exp + | datetime_value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +string_value_exp: + char_value_exp +/* | bit_value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + } +*/ ; +char_value_exp: + char_factor + | concatenation + ; +concatenation: + char_value_exp '+' char_factor + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("+", SQLNodeType::Punctuation)); + $$->append($3); + } + | value_exp SQL_CONCAT value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; + +char_primary: + SQL_TOKEN_STRING + | string_value_fct + ; +collate_clause: + SQL_TOKEN_COLLATE table_node + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +char_factor: + char_primary + | char_primary collate_clause + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +string_value_fct: + char_value_fct + | bit_value_fct + ; +bit_value_fct: + bit_substring_fct + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +bit_substring_fct: + SQL_TOKEN_SUBSTRING '(' bit_value_exp SQL_TOKEN_FROM string_value_exp for_length ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +bit_value_exp: + bit_factor + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +/* + bit_concatenation + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | +bit_concatenation: + bit_value_exp '+' bit_factor + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("+", SQLNodeType::Punctuation)); + $$->append($3); + } + ; +*/ +bit_factor: + bit_primary + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +bit_primary: + {$$ = SQL_NEW_RULE;} +/* value_exp_primary + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | string_value_fct + { + $$ = SQL_NEW_RULE; + $$->append($1); + }*/ + ; +char_value_fct: + char_substring_fct + | fold + | form_conversion + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | char_translation + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + | trim_fct + { + $$ = SQL_NEW_RULE; + $$->append($1); + } + ; +for_length: + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_FOR value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +char_substring_fct: + SQL_TOKEN_SUBSTRING '(' value_exp SQL_TOKEN_FROM value_exp for_length ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_SUBSTRING '(' value_exp_commalist ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +upper_lower: + SQL_TOKEN_UPPER + | SQL_TOKEN_LOWER + ; +fold: + upper_lower '(' value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +form_conversion: + SQL_TOKEN_CONVERT '(' string_value_exp SQL_TOKEN_USING table_node ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_CONVERT '(' cast_operand ',' cast_target ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(",", SQLNodeType::Punctuation)); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +char_translation: + SQL_TOKEN_TRANSLATE '(' string_value_exp SQL_TOKEN_USING table_node ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +trim_fct: + SQL_TOKEN_TRIM '(' trim_operands ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +trim_operands: + trim_spec value_exp SQL_TOKEN_FROM value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | trim_spec SQL_TOKEN_FROM value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | value_exp SQL_TOKEN_FROM value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_FROM value_exp + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | value_exp + ; + +trim_spec: + SQL_TOKEN_BOTH + | SQL_TOKEN_LEADING + | SQL_TOKEN_TRAILING + ; + +derived_column: + value_exp as_clause + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +/* Tabellenname */ +table_node: + table_name + | schema_name + | catalog_name +; +catalog_name: + SQL_TOKEN_NAME '.' schema_name + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($3); + } + | SQL_TOKEN_NAME ':' schema_name + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(":", SQLNodeType::Punctuation)); + $$->append($3); + } +; +schema_name: + SQL_TOKEN_NAME '.' table_name + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($3); + } +; + +table_name: + SQL_TOKEN_NAME + {$$ = SQL_NEW_RULE; + $$->append($1);} +; +/* Columns */ +column_ref: + column + {$$ = SQL_NEW_RULE; + $$->append($1);} +/* | table_node '.' column_val %prec '.' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($3);} +*/ + | SQL_TOKEN_NAME '.' column_val %prec '.' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($3); + } + | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($5);} + | SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($5); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($7); + } + | SQL_TOKEN_NAME ':' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val %prec '.' + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(":", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($5); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($7); + } +/* | SQL_TOKEN_NAME ';' SQL_TOKEN_NAME '.' SQL_TOKEN_NAME '.' column_val + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode(";", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($5); + $$->append(newNode(".", SQLNodeType::Punctuation)); + $$->append($7); + } +*/ ; + + /* data types */ +column_val: + column + {$$ = SQL_NEW_RULE; + $$->append($1);} + | '*' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("*", SQLNodeType::Punctuation)); + } + ; +data_type: + predefined_type + ; +opt_char_set_spec: + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_CHARACTER SQL_TOKEN_SET SQL_TOKEN_NAME + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +opt_collate_clause: + {$$ = SQL_NEW_RULE;} + | collate_clause + ; +predefined_type: + character_string_type opt_char_set_spec opt_collate_clause + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | national_character_string_type opt_collate_clause + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | binary_string_type + | numeric_type + | boolean_type + | datetime_type + | interval_type + ; +character_string_type: + SQL_TOKEN_CHARACTER opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_CHAR opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_CHARACTER SQL_TOKEN_VARYING paren_char_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_CHAR SQL_TOKEN_VARYING paren_char_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_VARCHAR paren_char_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | character_large_object_type + ; +opt_paren_precision: + {$$ = SQL_NEW_RULE;} + | paren_char_length + ; +paren_char_length: + '(' SQL_TOKEN_INTNUM ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +opt_paren_char_large_length: + {$$ = SQL_NEW_RULE;} + | paren_character_large_object_length + ; +paren_character_large_object_length: + '(' large_object_length ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; + +large_object_length: + SQL_TOKEN_INTNUM opt_multiplier + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +opt_multiplier: + {$$ = SQL_NEW_RULE;} + | 'K' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("K", SQLNodeType::Punctuation)); + } + | 'M' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("M", SQLNodeType::Punctuation)); + } + | 'G' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("G", SQLNodeType::Punctuation)); + } + | 'T' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("T", SQLNodeType::Punctuation)); + } + | 'P' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("P", SQLNodeType::Punctuation)); + } + ; +character_large_object_type: + SQL_TOKEN_CHARACTER SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_CHAR SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_CLOB opt_paren_char_large_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +national_character_string_type: + SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_NATIONAL SQL_TOKEN_CHAR opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_NCHAR opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER SQL_TOKEN_VARYING paren_char_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_NATIONAL SQL_TOKEN_CHAR SQL_TOKEN_VARYING paren_char_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_NCHAR SQL_TOKEN_VARYING paren_char_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | national_character_large_object_type + ; +national_character_large_object_type: + SQL_TOKEN_NATIONAL SQL_TOKEN_CHARACTER SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + } + | SQL_TOKEN_NCHAR SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_NCLOB opt_paren_char_large_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +binary_string_type: + SQL_TOKEN_BINARY opt_paren_precision + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_BINARY SQL_TOKEN_VARYING paren_char_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_VARBINARY paren_char_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | binary_large_object_string_type + ; +binary_large_object_string_type: + SQL_TOKEN_BINARY SQL_TOKEN_LARGE SQL_TOKEN_OBJECT opt_paren_char_large_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_BLOB opt_paren_char_large_length + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +numeric_type: + exact_numeric_type + | approximate_numeric_type + ; +opt_paren_precision_scale: + {$$ = SQL_NEW_RULE;} + | '(' SQL_TOKEN_INTNUM ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | '(' SQL_TOKEN_INTNUM ',' SQL_TOKEN_INTNUM ')' + { + $$ = SQL_NEW_RULE; + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode(",", SQLNodeType::Punctuation)); + $$->append($4); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +exact_numeric_type: + SQL_TOKEN_NUMERIC opt_paren_precision_scale + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_DECIMAL opt_paren_precision_scale + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_DEC opt_paren_precision_scale + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + | SQL_TOKEN_SMALLINT + | SQL_TOKEN_INTEGER + | SQL_TOKEN_INT + | SQL_TOKEN_BIGINT + ; +approximate_numeric_type: + SQL_TOKEN_FLOAT '(' SQL_TOKEN_INTNUM ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_FLOAT + | SQL_TOKEN_REAL + | SQL_TOKEN_DOUBLE + | SQL_TOKEN_DOUBLE SQL_TOKEN_PRECISION + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +boolean_type: + SQL_TOKEN_BOOLEAN +; +datetime_type: + SQL_TOKEN_DATE + | SQL_TOKEN_TIME opt_paren_precision opt_with_or_without_time_zone + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_TIMESTAMP opt_paren_precision opt_with_or_without_time_zone + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +opt_with_or_without_time_zone: + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_WITH SQL_TOKEN_TIME SQL_TOKEN_ZONE + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + | SQL_TOKEN_WITHOUT SQL_TOKEN_TIME SQL_TOKEN_ZONE + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +interval_type: + SQL_TOKEN_INTERVAL interval_qualifier + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; + /* the various things you can name */ + +column: + SQL_TOKEN_NAME + | SQL_TOKEN_POSITION + { + sal_uInt32 nNod = $$->getRuleID(); + delete $$; + $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name); + } + | SQL_TOKEN_CHAR_LENGTH + { + sal_uInt32 nNod = $$->getRuleID(); + delete $$; + $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name); + } + | SQL_TOKEN_EXTRACT + { + sal_uInt32 nNod = $$->getRuleID(); + delete $$; + $$ = newNode(OSQLParser::TokenIDToStr(nNod), SQLNodeType::Name); + } + ; +case_expression: + case_abbreviation + | case_specification + ; +case_abbreviation: + SQL_TOKEN_NULLIF '(' value_exp_commalist ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_COALESCE '(' value_exp ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + | SQL_TOKEN_COALESCE '(' value_exp_commalist ')' + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append(newNode("(", SQLNodeType::Punctuation)); + $$->append($3); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + ; +case_specification: + simple_case + | searched_case + ; +simple_case: + SQL_TOKEN_CASE case_operand simple_when_clause_list else_clause SQL_TOKEN_END + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + } + ; +searched_case: + SQL_TOKEN_CASE searched_when_clause_list else_clause SQL_TOKEN_END + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +simple_when_clause_list: + simple_when_clause + { + $$ = SQL_NEW_LISTRULE; + $$->append($1); + } + | searched_when_clause_list simple_when_clause + { + $1->append($2); + $$ = $1; + } + ; +simple_when_clause: + SQL_TOKEN_WHEN when_operand_list SQL_TOKEN_THEN result + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +when_operand_list: + when_operand + {$$ = SQL_NEW_COMMALISTRULE; + $$->append($1);} + | when_operand_list ',' when_operand + {$1->append($3); + $$ = $1;} + ; +when_operand: + row_value_constructor_elem + | comparison_predicate_part_2 %dprec 1 + | between_predicate_part_2 + | in_predicate_part_2 + | character_like_predicate_part_2 + | null_predicate_part_2 %dprec 2 +; +searched_when_clause_list: + searched_when_clause + { + $$ = SQL_NEW_LISTRULE; + $$->append($1); + } + | searched_when_clause_list searched_when_clause + { + $1->append($2); + $$ = $1; + } + ; +searched_when_clause: + SQL_TOKEN_WHEN search_condition SQL_TOKEN_THEN result + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + ; +else_clause: + {$$ = SQL_NEW_RULE;} + | SQL_TOKEN_ELSE result + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +result: + result_expression + ; +result_expression: + value_exp + ; +case_operand: + row_value_constructor_elem + ; + +cursor: SQL_TOKEN_NAME + {$$ = SQL_NEW_RULE; + $$->append($1);} + ; + +/*** +module: SQL_TOKEN_NAME + {$$ = SQL_NEW_RULE; + $$->append($1);} + ; +***/ + +parameter: + ':' SQL_TOKEN_NAME + {$$ = SQL_NEW_RULE; + $$->append(newNode(":", SQLNodeType::Punctuation)); + $$->append($2);} + | '?' + {$$ = SQL_NEW_RULE; // test + $$->append(newNode("?", SQLNodeType::Punctuation));} + | '[' SQL_TOKEN_NAME ']' + {$$ = SQL_NEW_RULE; + $$->append(newNode("[", SQLNodeType::Punctuation)); + $$->append($2); + $$->append(newNode("]", SQLNodeType::Punctuation));} + ; + +/*** +procedure: SQL_TOKEN_NAME + {$$ = SQL_NEW_RULE; + $$->append($1);} + ; +***/ + +range_variable: + {$$ = SQL_NEW_RULE;} + | opt_as SQL_TOKEN_NAME + {$$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; + +user: SQL_TOKEN_NAME + ; + +/* PREDICATECHECK RULES */ +sql: + search_condition /* checking predicats */ + { + if (xxx_pGLOBAL_SQLPARSER->inPredicateCheck()) // sql: rule 1 + { + $$ = $1; + if ( SQL_ISRULE($$,search_condition) ) + { + $$->insert(0,newNode("(", SQLNodeType::Punctuation)); + $$->append(newNode(")", SQLNodeType::Punctuation)); + } + } + else + YYERROR; + } + | '(' sql ')' /* checking predicats */ + ; +trigger_definition: + SQL_TOKEN_CREATE SQL_TOKEN_TRIGGER trigger_name trigger_action_time trigger_event SQL_TOKEN_ON table_name op_referencing triggered_action + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + $$->append($5); + $$->append($6); + $$->append($7); + $$->append($8); + $$->append($9); + } + ; +op_referencing: + { + $$ = SQL_NEW_RULE; + } + | SQL_TOKEN_REFERENCING transition_table_or_variable_list + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +trigger_action_time: + SQL_TOKEN_BEFORE + | SQL_TOKEN_AFTER + | SQL_TOKEN_INSTEAD SQL_TOKEN_OF + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } +; +trigger_event: + SQL_TOKEN_INSERT + | SQL_TOKEN_DELETE + | SQL_TOKEN_UPDATE op_trigger_columnlist + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +op_trigger_columnlist: + { + $$ = SQL_NEW_RULE; + } + | SQL_TOKEN_OF trigger_column_list + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +trigger_column_list: + column_commalist + ; +triggered_action: + op_triggered_action_for triggered_when_clause triggered_SQL_statement + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +op_triggered_action_for: + { + $$ = SQL_NEW_RULE; + } + | SQL_TOKEN_FOR SQL_TOKEN_EACH trigger_for + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + } + ; +trigger_for: + SQL_TOKEN_ROW + | SQL_TOKEN_STATEMENT + ; +triggered_when_clause: + { + $$ = SQL_NEW_RULE; + } + | SQL_TOKEN_WHEN parenthesized_boolean_value_expression + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + } + ; +triggered_SQL_statement: + SQL_procedure_statement + | SQL_TOKEN_BEGIN SQL_TOKEN_ATOMIC SQL_procedure_statement_list ';' SQL_TOKEN_END + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append(newNode(";", SQLNodeType::Punctuation)); + $$->append($5); + } + ; +SQL_procedure_statement_list: + SQL_procedure_statement + { + $$ = SQL_NEW_LISTRULE; + $$->append($1); + } + | SQL_procedure_statement_list ';' SQL_procedure_statement + { + $1->append($3); + $$ = $1; + } + ; +SQL_procedure_statement: + sql + ; + +transition_table_or_variable_list: + transition_table_or_variable + { + $$ = SQL_NEW_LISTRULE; + $$->append($1); + } + | transition_table_or_variable_list transition_table_or_variable + { + $1->append($2); + $$ = $1; + } + ; + +transition_table_or_variable: + SQL_TOKEN_OLD opt_row opt_as old_transition_variable_name + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_NEW opt_row opt_as new_transition_variable_name + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_OLD SQL_TOKEN_TABLE opt_as old_transition_table_name + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } + | SQL_TOKEN_NEW SQL_TOKEN_TABLE opt_as new_transition_table_name + { + $$ = SQL_NEW_RULE; + $$->append($1); + $$->append($2); + $$->append($3); + $$->append($4); + } +; +old_transition_table_name: + transition_table_name +; +new_transition_table_name: + transition_table_name +; +transition_table_name: + SQL_TOKEN_NAME +; +old_transition_variable_name: + SQL_TOKEN_NAME +; +new_transition_variable_name: + SQL_TOKEN_NAME +; +trigger_name: + SQL_TOKEN_NAME +; +%% + +#if defined _MSC_VER +#pragma warning(pop) +#endif + +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::osl; +using namespace ::dbtools; + +connectivity::OSQLParser* xxx_pGLOBAL_SQLPARSER; + +connectivity::OSQLInternalNode* newNode(const char* pNewValue, + const connectivity::SQLNodeType eNodeType, + const sal_uInt32 nNodeID) +{ + return new connectivity::OSQLInternalNode(pNewValue, eNodeType, nNodeID); +} + +connectivity::OSQLInternalNode* newNode(const OString& _newValue, + const connectivity::SQLNodeType eNodeType, + const sal_uInt32 nNodeID) +{ + return new connectivity::OSQLInternalNode(_newValue, eNodeType, nNodeID); +} + +connectivity::OSQLInternalNode* newNode(const OUString& _newValue, + const connectivity::SQLNodeType eNodeType, + const sal_uInt32 nNodeID) +{ + return new connectivity::OSQLInternalNode(_newValue, eNodeType, nNodeID); +} + +OParseContext::OParseContext() +{ +} + + +OParseContext::~OParseContext() +{ +} + + +OUString OParseContext::getErrorMessage(ErrorCode _eCode) const +{ + OUString aMsg; + switch (_eCode) + { + case ErrorCode::General: aMsg = "Syntax error in SQL expression"; break; + case ErrorCode::ValueNoLike: aMsg = "The value #1 can not be used with LIKE."; break; + case ErrorCode::FieldNoLike: aMsg = "LIKE can not be used with this field."; break; + case ErrorCode::InvalidCompare: aMsg = "The entered criterion can not be compared with this field."; break; + case ErrorCode::InvalidIntCompare: aMsg = "The field can not be compared with a number."; break; + case ErrorCode::InvalidDateCompare: aMsg = "The field can not be compared with a date."; break; + case ErrorCode::InvalidRealCompare: aMsg = "The field can not be compared with a floating point number."; break; + case ErrorCode::InvalidTableNosuch: aMsg = "The database does not contain a table named \"#\"."; break; + case ErrorCode::InvalidTableOrQuery: aMsg = "The database does contain neither a table nor a query named \"#\"."; break; + case ErrorCode::InvalidColumn: aMsg = "The column \"#1\" is unknown in the table \"#2\"."; break; + case ErrorCode::InvalidTableExist: aMsg = "The database already contains a table or view with name \"#\"."; break; + case ErrorCode::InvalidQueryExist: aMsg = "The database already contains a query with name \"#\"."; break; + default: + OSL_FAIL( "OParseContext::getErrorMessage: unknown error code!" ); + break; + } + return aMsg; +} + + +OString OParseContext::getIntlKeywordAscii(InternationalKeyCode _eKey) const +{ + OString aKeyword; + switch (_eKey) + { + case InternationalKeyCode::Like: aKeyword = "LIKE"; break; + case InternationalKeyCode::Not: aKeyword = "NOT"; break; + case InternationalKeyCode::Null: aKeyword = "NULL"; break; + case InternationalKeyCode::True: aKeyword = "True"; break; + case InternationalKeyCode::False: aKeyword = "False"; break; + case InternationalKeyCode::Is: aKeyword = "IS"; break; + case InternationalKeyCode::Between: aKeyword = "BETWEEN"; break; + case InternationalKeyCode::Or: aKeyword = "OR"; break; + case InternationalKeyCode::And: aKeyword = "AND"; break; + case InternationalKeyCode::Avg: aKeyword = "AVG"; break; + case InternationalKeyCode::Count: aKeyword = "COUNT"; break; + case InternationalKeyCode::Max: aKeyword = "MAX"; break; + case InternationalKeyCode::Min: aKeyword = "MIN"; break; + case InternationalKeyCode::Sum: aKeyword = "SUM"; break; + case InternationalKeyCode::Every: aKeyword = "EVERY"; break; + case InternationalKeyCode::Any: aKeyword = "ANY"; break; + case InternationalKeyCode::Some: aKeyword = "SOME"; break; + case InternationalKeyCode::StdDevPop: aKeyword = "STDDEV_POP"; break; + case InternationalKeyCode::StdDevSamp: aKeyword = "STDDEV_SAMP"; break; + case InternationalKeyCode::VarSamp: aKeyword = "VAR_SAMP"; break; + case InternationalKeyCode::VarPop: aKeyword = "VAR_POP"; break; + case InternationalKeyCode::Collect: aKeyword = "COLLECT"; break; + case InternationalKeyCode::Fusion: aKeyword = "FUSION"; break; + case InternationalKeyCode::Intersection:aKeyword = "INTERSECTION"; break; + case InternationalKeyCode::None: break; + default: + OSL_FAIL( "OParseContext::getIntlKeywordAscii: unknown key!" ); + break; + } + return aKeyword; +} + + +IParseContext::InternationalKeyCode OParseContext::getIntlKeyCode(const OString& rToken) const +{ + static IParseContext::InternationalKeyCode Intl_TokenID[] = + { + InternationalKeyCode::Like, InternationalKeyCode::Not, InternationalKeyCode::Null, InternationalKeyCode::True, + InternationalKeyCode::False, InternationalKeyCode::Is, InternationalKeyCode::Between, InternationalKeyCode::Or, + InternationalKeyCode::And, InternationalKeyCode::Avg, InternationalKeyCode::Count, InternationalKeyCode::Max, + InternationalKeyCode::Min, InternationalKeyCode::Sum, InternationalKeyCode::Every,InternationalKeyCode::Any,InternationalKeyCode::Some, + InternationalKeyCode::StdDevPop,InternationalKeyCode::StdDevSamp,InternationalKeyCode::VarSamp, + InternationalKeyCode::VarPop,InternationalKeyCode::Collect,InternationalKeyCode::Fusion,InternationalKeyCode::Intersection + }; + + sal_uInt32 nCount = SAL_N_ELEMENTS( Intl_TokenID ); + for (sal_uInt32 i = 0; i < nCount; i++) + { + OString aKey = getIntlKeywordAscii(Intl_TokenID[i]); + if (rToken.equalsIgnoreAsciiCase(aKey)) + return Intl_TokenID[i]; + } + + return InternationalKeyCode::None; +} + + +static Locale& impl_getLocaleInstance( ) +{ + static Locale s_aLocale( "en", "US", "" ); + return s_aLocale; +} + + +Locale OParseContext::getPreferredLocale( ) const +{ + return getDefaultLocale(); +} + + +const Locale& OParseContext::getDefaultLocale() +{ + return impl_getLocaleInstance(); +} + +// The (unfortunately global) yylval for the handing over of +// values from the Scanner to the Parser. The global variable +// is only used for a short term, the Parser reads the variable +// immediately after the call of the Scanner into a same named own +// member variable. + + +OUString ConvertLikeToken(const OSQLParseNode* pTokenNode, const OSQLParseNode* pEscapeNode, bool bInternational) +{ + OUStringBuffer aMatchStr(0); + if (pTokenNode->isToken()) + { + sal_Unicode cEscape = 0; + if (pEscapeNode->count()) + cEscape = pEscapeNode->getChild(1)->getTokenValue().toChar(); + + // Change place holder + aMatchStr = pTokenNode->getTokenValue(); + const sal_Int32 nLen = aMatchStr.getLength(); + OUStringBuffer sSearch,sReplace; + if ( bInternational ) + { + sSearch.append("%_"); + sReplace.append("*?"); + } + else + { + sSearch.append("*?"); + sReplace.append("%_"); + } + + bool wasEscape = false; + for (sal_Int32 i = 0; i < nLen; i++) + { + const sal_Unicode c = aMatchStr[i]; + // SQL standard requires the escape to be followed + // by a meta-character ('%', '_' or itself), else error + // We are more lenient here and let it escape anything. + // Especially since some databases (e.g. Microsoft SQL Server) + // have more meta-characters than the standard, such as e.g. '[' and ']' + if (wasEscape) + { + wasEscape=false; + continue; + } + if (c == cEscape) + { + wasEscape=true; + continue; + } + int match = -1; + if (c == sSearch[0]) + match=0; + else if (c == sSearch[1]) + match=1; + + if (match != -1) + { + aMatchStr[i] = sReplace[match]; + } + } + } + return aMatchStr.makeStringAndClear(); +} + +sal_uInt32 OSQLParser::s_nRuleIDs[OSQLParseNode::rule_count + 1]; +OSQLParser::RuleIDMap OSQLParser::s_aReverseRuleIDLookup; +OParseContext OSQLParser::s_aDefaultContext; + +sal_Int32 OSQLParser::s_nRefCount = 0; +// ::osl::Mutex OSQLParser::s_aMutex; +OSQLScanner* OSQLParser::s_pScanner = nullptr; +OSQLParseNodesGarbageCollector* OSQLParser::s_pGarbageCollector = nullptr; +css::uno::Reference< css::i18n::XLocaleData4> OSQLParser::s_xLocaleData = nullptr; + +void setParser(OSQLParser* _pParser) +{ + xxx_pGLOBAL_SQLPARSER = _pParser; +} + +void OSQLParser::setParseTree(OSQLParseNode* pNewParseTree) +{ + ::osl::MutexGuard aGuard(getMutex()); + m_pParseTree.reset(pNewParseTree); +} + + +/** Delete all comments in a query. + + See also getComment()/concatComment() implementation for + OQueryController::translateStatement(). + */ +static OUString delComment( const OUString& rQuery ) +{ + // First a quick search if there is any "--" or "//" or "/*", if not then the whole + // copying loop is pointless. + if (rQuery.indexOf("--") < 0 && rQuery.indexOf("//") < 0 && + rQuery.indexOf("/*") < 0) + return rQuery; + + const sal_Unicode* pCopy = rQuery.getStr(); + sal_Int32 nQueryLen = rQuery.getLength(); + bool bIsText1 = false; // "text" + bool bIsText2 = false; // 'text' + bool bComment2 = false; // /* comment */ + bool bComment = false; // -- or // comment + OUStringBuffer aBuf(nQueryLen); + for (sal_Int32 i=0; i < nQueryLen; ++i) + { + if (bComment2) + { + if ((i+1) < nQueryLen) + { + if (pCopy[i]=='*' && pCopy[i+1]=='/') + { + bComment2 = false; + ++i; + } + } + else + { + // comment can't close anymore, actually an error, but... + } + continue; + } + if (pCopy[i] == '\n') + bComment = false; + else if (!bComment) + { + if (pCopy[i] == '\"' && !bIsText2) + bIsText1 = !bIsText1; + else if (pCopy[i] == '\'' && !bIsText1) + bIsText2 = !bIsText2; + if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen) + { + if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/')) + bComment = true; + else if ((pCopy[i]=='/' && pCopy[i+1]=='*')) + bComment2 = true; + } + } + if (!bComment && !bComment2) + aBuf.append( &pCopy[i], 1); + } + return aBuf.makeStringAndClear(); +} + +std::unique_ptr<OSQLParseNode> OSQLParser::parseTree(OUString& rErrorMessage, + const OUString& rStatement, + bool bInternational) +{ + + + // Guard the parsing + ::osl::MutexGuard aGuard(getMutex()); + // must be reset + setParser(this); + + // delete comments before parsing + OUString sTemp = delComment(rStatement); + + // defines how to scan + s_pScanner->SetRule(OSQLScanner::GetSQLRule()); // initial + s_pScanner->prepareScan(sTemp, m_pContext, bInternational); + + SQLyylval.pParseNode = nullptr; + // SQLyypvt = NULL; + m_pParseTree = nullptr; + m_sErrorMessage = ""; + + // start parsing + if (SQLyyparse() != 0) + { + // only set the error message, if it's not already set + if (m_sErrorMessage.isEmpty()) + m_sErrorMessage = s_pScanner->getErrorMessage(); + if (m_sErrorMessage.isEmpty()) + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::General); + + rErrorMessage = m_sErrorMessage; + + // clear the garbage collector + (*s_pGarbageCollector)->clearAndDelete(); + m_pParseTree.release(); // because the garbage collector deleted it + return nullptr; + } + else + { + (*s_pGarbageCollector)->clear(); + + // return result: + // to work around a bug in MKS YACC return the member m_pParseTree + // instead of Sdbyyval.pParseNode + + SAL_WARN_IF(!m_pParseTree, "connectivity.parse", + "OSQLParser: Parser did not create ParseTree"); + return std::move(m_pParseTree); + } +} + +OString OSQLParser::TokenIDToStr(sal_uInt32 nTokenID, const IParseContext* pContext) +{ + OString aStr; + if (pContext) + { + IParseContext::InternationalKeyCode eKeyCode = IParseContext::InternationalKeyCode::None; + switch( nTokenID ) + { + case SQL_TOKEN_LIKE: eKeyCode = IParseContext::InternationalKeyCode::Like; break; + case SQL_TOKEN_NOT: eKeyCode = IParseContext::InternationalKeyCode::Not; break; + case SQL_TOKEN_NULL: eKeyCode = IParseContext::InternationalKeyCode::Null; break; + case SQL_TOKEN_TRUE: eKeyCode = IParseContext::InternationalKeyCode::True; break; + case SQL_TOKEN_FALSE: eKeyCode = IParseContext::InternationalKeyCode::False; break; + case SQL_TOKEN_IS: eKeyCode = IParseContext::InternationalKeyCode::Is; break; + case SQL_TOKEN_BETWEEN: eKeyCode = IParseContext::InternationalKeyCode::Between; break; + case SQL_TOKEN_OR: eKeyCode = IParseContext::InternationalKeyCode::Or; break; + case SQL_TOKEN_AND: eKeyCode = IParseContext::InternationalKeyCode::And; break; + case SQL_TOKEN_AVG: eKeyCode = IParseContext::InternationalKeyCode::Avg; break; + case SQL_TOKEN_COUNT: eKeyCode = IParseContext::InternationalKeyCode::Count; break; + case SQL_TOKEN_MAX: eKeyCode = IParseContext::InternationalKeyCode::Max; break; + case SQL_TOKEN_MIN: eKeyCode = IParseContext::InternationalKeyCode::Min; break; + case SQL_TOKEN_SUM: eKeyCode = IParseContext::InternationalKeyCode::Sum; break; + } + if ( eKeyCode != IParseContext::InternationalKeyCode::None ) + aStr = pContext->getIntlKeywordAscii(eKeyCode); + } + + if (aStr.isEmpty()) + { + aStr = yytname[YYTRANSLATE(nTokenID)]; + if(aStr.startsWith("SQL_TOKEN_")) + aStr = aStr.copy(10); + switch( nTokenID ) + { + case SQL_TOKEN_OJ: + case SQL_TOKEN_TS: + case SQL_TOKEN_T: + case SQL_TOKEN_D: + aStr = aStr.toAsciiLowerCase(); + } + } + return aStr; +} + +#if OSL_DEBUG_LEVEL > 0 +OUString OSQLParser::RuleIDToStr(sal_uInt32 nRuleID) +{ + OSL_ENSURE(nRuleID < SAL_N_ELEMENTS(yytname), "OSQLParser::RuleIDToStr: Invalid nRuleId!"); + return OUString::createFromAscii(yytname[nRuleID]); +} +#endif + + +sal_uInt32 OSQLParser::StrToRuleID(const OString & rValue) +{ + // Search for the given name in yytname and return the index + // (or UNKNOWN_RULE, if not found) + static sal_uInt32 nLen = SAL_N_ELEMENTS(yytname); + for (sal_uInt32 i = YYTRANSLATE(SQL_TOKEN_INVALIDSYMBOL); i < (nLen-1); i++) + { + if (rValue == yytname[i]) + return i; + } + + // Not found + return OSQLParseNode::UNKNOWN_RULE; +} + + +OSQLParseNode::Rule OSQLParser::RuleIDToRule( sal_uInt32 _nRule ) +{ + OSQLParser::RuleIDMap::const_iterator i (s_aReverseRuleIDLookup.find(_nRule)); + if (i == s_aReverseRuleIDLookup.end()) + { + SAL_INFO("connectivity.parse", + "connectivity::OSQLParser::RuleIDToRule cannot reverse-lookup rule. " + "Reverse mapping incomplete? " + "_nRule='" << _nRule << "' " + "yytname[_nRule]='" << yytname[_nRule] << "'"); + return OSQLParseNode::UNKNOWN_RULE; + } + else + return i->second; +} + + +sal_uInt32 OSQLParser::RuleID(OSQLParseNode::Rule eRule) +{ + return s_nRuleIDs[(sal_uInt16)eRule]; +} + +sal_Int16 OSQLParser::buildNode(OSQLParseNode*& pAppend,OSQLParseNode* pCompare,OSQLParseNode* pLiteral,OSQLParseNode* pLiteral2) +{ + OSQLParseNode* pColumnRef = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::column_ref)); + pColumnRef->append(new OSQLInternalNode(m_sFieldName,SQLNodeType::Name)); + OSQLParseNode* pComp = nullptr; + if ( SQL_ISTOKEN( pCompare, BETWEEN) && pLiteral2 ) + pComp = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::between_predicate_part_2)); + else + pComp = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::comparison_predicate)); + + pComp->append(pColumnRef); + pComp->append(pCompare); + pComp->append(pLiteral); + if ( pLiteral2 ) + { + pComp->append(new OSQLInternalNode("", SQLNodeType::Keyword,SQL_TOKEN_AND)); + pComp->append(pLiteral2); + } + pAppend->append(pComp); + return 1; +} + +sal_Int16 OSQLParser::buildStringNodes(OSQLParseNode*& pLiteral) +{ + if(!pLiteral) + return 1; + + if(SQL_ISRULE(pLiteral,set_fct_spec) || SQL_ISRULE(pLiteral,general_set_fct) || SQL_ISRULE(pLiteral,column_ref) + || SQL_ISRULE(pLiteral,subquery)) + return 1; // here I have a function that I can't transform into a string + + if(pLiteral->getNodeType() == SQLNodeType::IntNum || pLiteral->getNodeType() == SQLNodeType::ApproxNum || pLiteral->getNodeType() == SQLNodeType::AccessDate) + { + OSQLParseNode* pParent = pLiteral->getParent(); + + OSQLParseNode* pNewNode = new OSQLInternalNode(pLiteral->getTokenValue(), SQLNodeType::String); + pParent->replace(pLiteral, pNewNode); + delete pLiteral; + pLiteral = nullptr; + return 1; + } + + for(size_t i=0;i<pLiteral->count();++i) + { + OSQLParseNode* pChild = pLiteral->getChild(i); + buildStringNodes(pChild); + } + if(SQL_ISRULE(pLiteral,term) || SQL_ISRULE(pLiteral,value_exp_primary)) + { + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare); + return 0; + } + return 1; +} + +sal_Int16 OSQLParser::buildComparisonRule(OSQLParseNode*& pAppend,OSQLParseNode* pLiteral) +{ + OSQLParseNode* pComp = new OSQLInternalNode("=", SQLNodeType::Equal); + return buildPredicateRule(pAppend,pLiteral,pComp); +} + + + +void OSQLParser::reduceLiteral(OSQLParseNode*& pLiteral, bool bAppendBlank) +{ + OSL_ENSURE(pLiteral->isRule(), "This is no Rule"); + OSL_ENSURE(pLiteral->count() == 2, "OSQLParser::ReduceLiteral() Invalid count"); + OSQLParseNode* pTemp = pLiteral; + OUStringBuffer aValue(pLiteral->getChild(0)->getTokenValue()); + if (bAppendBlank) + { + aValue.append(" "); + } + + aValue.append(pLiteral->getChild(1)->getTokenValue()); + + pLiteral = new OSQLInternalNode(aValue.makeStringAndClear(),SQLNodeType::String); + delete pTemp; +} + + +void OSQLParser::error(const char *fmt) +{ + if(m_sErrorMessage.isEmpty()) + { + OUString sStr(fmt,strlen(fmt),RTL_TEXTENCODING_UTF8); + OUString sSQL_TOKEN("SQL_TOKEN_"); + + sal_Int32 nPos1 = sStr.indexOf(sSQL_TOKEN); + if(nPos1 != -1) + { + OUString sFirst = sStr.copy(0,nPos1); + sal_Int32 nPos2 = sStr.indexOf(sSQL_TOKEN,nPos1+1); + if(nPos2 != -1) + { + OUString sSecond = sStr.copy(nPos1+sSQL_TOKEN.getLength(),nPos2-nPos1-sSQL_TOKEN.getLength()); + sFirst += sSecond; + sFirst += sStr.copy(nPos2+sSQL_TOKEN.getLength()); + } + else + sFirst += sStr.copy(nPos1+sSQL_TOKEN.getLength()); + + m_sErrorMessage = sFirst; + } + else + m_sErrorMessage = sStr; + + OUString aError = s_pScanner->getErrorMessage(); + if(!aError.isEmpty()) + { + m_sErrorMessage += ", "; + m_sErrorMessage += aError; + } + } +} + +int OSQLParser::SQLlex() +{ + return OSQLScanner::SQLlex(); +} diff --git a/connectivity/source/parse/sqlflex.l b/connectivity/source/parse/sqlflex.l new file mode 100644 index 000000000..34a4067ea --- /dev/null +++ b/connectivity/source/parse/sqlflex.l @@ -0,0 +1,808 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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" + +#define YY_EXIT 1 // YY_FATAL will not halt the application + +#ifndef _CSTDARG_ +#include <cstdarg> +#endif + +#include <string.h> + +#if defined _MSC_VER +#pragma warning ( push ) +// Silence warnings about redefinition of INT8_MIN etc in stdint.h +// The flex-generated workdir/LexTarget/idlc/source/scanner.cxx defines them prior to these includes +#pragma warning ( disable : 4005 ) +#endif +#include <connectivity/internalnode.hxx> +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#ifndef INCLUDED_CONNECTIVITY_SOURCE_PARSE_SQLFLEX_L +#define INCLUDED_CONNECTIVITY_SOURCE_PARSE_SQLFLEX_L + +#ifndef SQLYYDEBUG +#define SQLYYDEBUG 1 +#endif + +#include "sqlbison.hxx" +#undef SQLyylex +#undef SQLyyerror +#endif +#include <osl/diagnose.h> +#include <rtl/strbuf.hxx> +#include <connectivity/sqlparse.hxx> +#include <connectivity/sqlscan.hxx> + +#if defined _MSC_VER +/**/ +#ifdef yywrap +#undef yywrap +#define yywrap() 1 +#endif +/**/ +#endif +#define YY_NO_UNISTD_H + +using namespace connectivity; + +// Creation of the pages for the tokens +// Pages generally are created from the Lexer + +static sal_Int32 gatherString(int delim, sal_Int32 nTyp); +static sal_Int32 gatherName(const char*); +static sal_Int32 gatherNamePre(const char* ); +// has to be set before the parser starts +OSQLScanner* xxx_pGLOBAL_SQLSCAN = nullptr; + +#define SQL_NEW_NODE(text, token) \ + SQLyylval.pParseNode = new OSQLInternalNode(text, token); + +#define SQL_NEW_KEYWORD(token) \ + SQLyylval.pParseNode = new OSQLInternalNode("", SQLNodeType::Keyword, (token)); return token; + +#define SQL_NEW_INTNUM SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::IntNum); return SQL_TOKEN_INTNUM; +#define SQL_NEW_APPROXNUM SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::ApproxNum); return SQL_TOKEN_APPROXNUM; +#define SQL_NEW_DATE SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::AccessDate); return SQL_TOKEN_ACCESS_DATE; + +#define YY_INPUT(buf,result,max_size) \ +{ \ + int c = xxx_pGLOBAL_SQLSCAN->SQLyygetc(); \ + result = (c == EOF) ? YY_NULL : (buf[0] = c, 1);\ +} + +// coverity[+kill] +static void do_fatal_error(const char* msg) +{ + xxx_pGLOBAL_SQLSCAN->SQLyyerror(msg); + /*hack to silence -Wunused-function*/ + if ((0)) yy_fatal_error(msg); +} + +#define YY_FATAL_ERROR(msg) \ +{ \ + do_fatal_error(msg); \ +} + +%} + +%s SQL +%s PREDICATE_ENG +%s PREDICATE_GER +%s DATE +%s STRING + +%option noyywrap +%option never-interactive +%% + +ABS {SQL_NEW_KEYWORD(SQL_TOKEN_ABS); } +ACOS {SQL_NEW_KEYWORD(SQL_TOKEN_ACOS); } +AFTER {SQL_NEW_KEYWORD(SQL_TOKEN_AFTER); } +ALL {SQL_NEW_KEYWORD(SQL_TOKEN_ALL); } +ALTER {SQL_NEW_KEYWORD(SQL_TOKEN_ALTER); } +AND {SQL_NEW_KEYWORD(SQL_TOKEN_AND); } +ANY {SQL_NEW_KEYWORD(SQL_TOKEN_ANY); } +ARRAY_AGG {SQL_NEW_KEYWORD(SQL_TOKEN_ARRAY_AGG); } +AS {SQL_NEW_KEYWORD(SQL_TOKEN_AS); } +ASC {SQL_NEW_KEYWORD(SQL_TOKEN_ASC); } +ASCII {SQL_NEW_KEYWORD(SQL_TOKEN_ASCII); } +ASIN {SQL_NEW_KEYWORD(SQL_TOKEN_ASIN); } +AT {SQL_NEW_KEYWORD(SQL_TOKEN_AT); } +ATAN {SQL_NEW_KEYWORD(SQL_TOKEN_ATAN); } +ATAN2 {SQL_NEW_KEYWORD(SQL_TOKEN_ATAN2); } +ATOMIC {SQL_NEW_KEYWORD(SQL_TOKEN_ATOMIC); } +AUTHORIZATION {SQL_NEW_KEYWORD(SQL_TOKEN_AUTHORIZATION); } +AVG {SQL_NEW_KEYWORD(SQL_TOKEN_AVG); } + +BEFORE {SQL_NEW_KEYWORD(SQL_TOKEN_BEFORE); } +BEGIN {SQL_NEW_KEYWORD(SQL_TOKEN_BEGIN); } +BETWEEN {SQL_NEW_KEYWORD(SQL_TOKEN_BETWEEN); } +BIGINT {SQL_NEW_KEYWORD(SQL_TOKEN_BIGINT); } +BINARY {SQL_NEW_KEYWORD(SQL_TOKEN_BINARY); } +BIT {SQL_NEW_KEYWORD(SQL_TOKEN_BIT); } +BIT_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_BIT_LENGTH); } +BLOB {SQL_NEW_KEYWORD(SQL_TOKEN_BLOB); } +BOTH {SQL_NEW_KEYWORD(SQL_TOKEN_BOTH); } +BY {SQL_NEW_KEYWORD(SQL_TOKEN_BY); } + +CALL {SQL_NEW_KEYWORD(SQL_TOKEN_CALL); } +CASE {SQL_NEW_KEYWORD(SQL_TOKEN_CASE); } +CAST {SQL_NEW_KEYWORD(SQL_TOKEN_CAST); } +CEILING {SQL_NEW_KEYWORD(SQL_TOKEN_CEILING); } +CHAR {SQL_NEW_KEYWORD(SQL_TOKEN_CHAR); } +CHARACTER {SQL_NEW_KEYWORD(SQL_TOKEN_CHARACTER); } +CHAR(ACTER)?_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_CHAR_LENGTH); } +CHECK {SQL_NEW_KEYWORD(SQL_TOKEN_CHECK); } +CLOB {SQL_NEW_KEYWORD(SQL_TOKEN_CLOB); } +COALESCE {SQL_NEW_KEYWORD(SQL_TOKEN_COALESCE); } +COLLATE {SQL_NEW_KEYWORD(SQL_TOKEN_COLLATE); } +COLLECT {SQL_NEW_KEYWORD(SQL_TOKEN_COLLECT); } +COMMIT {SQL_NEW_KEYWORD(SQL_TOKEN_COMMIT); } +CONCAT {SQL_NEW_KEYWORD(SQL_TOKEN_CONCAT); } +CONTINUE {SQL_NEW_KEYWORD(SQL_TOKEN_CONTINUE); } +CONVERT {SQL_NEW_KEYWORD(SQL_TOKEN_CONVERT); } +COS {SQL_NEW_KEYWORD(SQL_TOKEN_COS); } +COT {SQL_NEW_KEYWORD(SQL_TOKEN_COT); } +COUNT {SQL_NEW_KEYWORD(SQL_TOKEN_COUNT); } +CREATE {SQL_NEW_KEYWORD(SQL_TOKEN_CREATE); } +CROSS {SQL_NEW_KEYWORD(SQL_TOKEN_CROSS); } +CUME_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_CUME_DIST); } +CURRENT {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT); } +CURRENT_DATE {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_DATE); } +CURRENT_CATALOG {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_CATALOG); } +CURRENT_DEFAULT_TRANSFORM_GROUP {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_DEFAULT_TRANSFORM_GROUP); } +CURRENT_PATH {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_PATH); } +CURRENT_ROLE {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_ROLE); } +CURRENT_SCHEMA {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_SCHEMA); } +CURRENT_USER {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_USER); } +CURDATE {SQL_NEW_KEYWORD(SQL_TOKEN_CURDATE); } +CURRENT_TIME {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_TIME); } +CURTIME {SQL_NEW_KEYWORD(SQL_TOKEN_CURTIME); } +CURRENT_TIMESTAMP {SQL_NEW_KEYWORD(SQL_TOKEN_CURRENT_TIMESTAMP); } +CURSOR {SQL_NEW_KEYWORD(SQL_TOKEN_CURSOR); } + +D {SQL_NEW_KEYWORD(SQL_TOKEN_D); } +DATE {SQL_NEW_KEYWORD(SQL_TOKEN_DATE); } +DATEDIFF {SQL_NEW_KEYWORD(SQL_TOKEN_DATEDIFF); } +DATEVALUE {SQL_NEW_KEYWORD(SQL_TOKEN_DATEVALUE); } +DAY {SQL_NEW_KEYWORD(SQL_TOKEN_DAY); } +DAYNAME {SQL_NEW_KEYWORD(SQL_TOKEN_DAYNAME); } +DAYOFMONTH {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFMONTH); } +DAYOFWEEK {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFWEEK); } +DAYOFYEAR {SQL_NEW_KEYWORD(SQL_TOKEN_DAYOFYEAR); } +DEC {SQL_NEW_KEYWORD(SQL_TOKEN_DEC); } +DECIMAL {SQL_NEW_KEYWORD(SQL_TOKEN_DECIMAL); } +DECLARE {SQL_NEW_KEYWORD(SQL_TOKEN_DECLARE); } +DEFAULT {SQL_NEW_KEYWORD(SQL_TOKEN_DEFAULT); } +DEGREES {SQL_NEW_KEYWORD(SQL_TOKEN_DEGREES); } +DELETE {SQL_NEW_KEYWORD(SQL_TOKEN_DELETE); } +DENSE_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_DENSE_RANK); } +DESC {SQL_NEW_KEYWORD(SQL_TOKEN_DESC); } +DIFFERENCE {SQL_NEW_KEYWORD(SQL_TOKEN_DIFFERENCE); } +DISTINCT {SQL_NEW_KEYWORD(SQL_TOKEN_DISTINCT); } +DOUBLE {SQL_NEW_KEYWORD(SQL_TOKEN_DOUBLE); } +DROP {SQL_NEW_KEYWORD(SQL_TOKEN_DROP); } + +EACH {SQL_NEW_KEYWORD(SQL_TOKEN_EACH); } +ELSE {SQL_NEW_KEYWORD(SQL_TOKEN_ELSE); } +END {SQL_NEW_KEYWORD(SQL_TOKEN_END); } +EVERY {SQL_NEW_KEYWORD(SQL_TOKEN_EVERY); } +ESCAPE {SQL_NEW_KEYWORD(SQL_TOKEN_ESCAPE); } +EXCEPT {SQL_NEW_KEYWORD(SQL_TOKEN_EXCEPT); } +EXCLUDE {SQL_NEW_KEYWORD(SQL_TOKEN_EXCLUDE); } +EXISTS {SQL_NEW_KEYWORD(SQL_TOKEN_EXISTS); } +EXP {SQL_NEW_KEYWORD(SQL_TOKEN_EXP); } +EXTRACT {SQL_NEW_KEYWORD(SQL_TOKEN_EXTRACT); } + +FALSE {SQL_NEW_KEYWORD(SQL_TOKEN_FALSE); } +FETCH {SQL_NEW_KEYWORD(SQL_TOKEN_FETCH); } +FIRST {SQL_NEW_KEYWORD(SQL_TOKEN_FIRST); } +FIRST_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_FIRST_VALUE); } +FLOAT {SQL_NEW_KEYWORD(SQL_TOKEN_FLOAT); } +FLOOR {SQL_NEW_KEYWORD(SQL_TOKEN_FLOOR); } +FN {SQL_NEW_KEYWORD(SQL_TOKEN_FN); } +FOLLOWING {SQL_NEW_KEYWORD(SQL_TOKEN_FOLLOWING); } +FOR {SQL_NEW_KEYWORD(SQL_TOKEN_FOR); } +FOREIGN {SQL_NEW_KEYWORD(SQL_TOKEN_FOREIGN); } +FOUND {SQL_NEW_KEYWORD(SQL_TOKEN_FOUND); } +FROM {SQL_NEW_KEYWORD(SQL_TOKEN_FROM); } +FULL {SQL_NEW_KEYWORD(SQL_TOKEN_FULL); } +FUSION {SQL_NEW_KEYWORD(SQL_TOKEN_FUSION); } + +GRANT {SQL_NEW_KEYWORD(SQL_TOKEN_GRANT); } +GROUP {SQL_NEW_KEYWORD(SQL_TOKEN_GROUP); } + +HAVING {SQL_NEW_KEYWORD(SQL_TOKEN_HAVING); } +HOUR {SQL_NEW_KEYWORD(SQL_TOKEN_HOUR); } + +IGNORE {SQL_NEW_KEYWORD(SQL_TOKEN_IGNORE); } +IN {SQL_NEW_KEYWORD(SQL_TOKEN_IN); } +INNER {SQL_NEW_KEYWORD(SQL_TOKEN_INNER); } +INSERT {SQL_NEW_KEYWORD(SQL_TOKEN_INSERT); } +INSTEAD {SQL_NEW_KEYWORD(SQL_TOKEN_INSTEAD); } +INT(EGER)? {SQL_NEW_KEYWORD(SQL_TOKEN_INTEGER); } +INTERSECT {SQL_NEW_KEYWORD(SQL_TOKEN_INTERSECT); } +INTERVAL {SQL_NEW_KEYWORD(SQL_TOKEN_INTERVAL); } +INTERSECTION {SQL_NEW_KEYWORD(SQL_TOKEN_INTERSECTION); } +INTO {SQL_NEW_KEYWORD(SQL_TOKEN_INTO); } +IS {SQL_NEW_KEYWORD(SQL_TOKEN_IS); } + +JOIN {SQL_NEW_KEYWORD(SQL_TOKEN_JOIN); } + +KEY {SQL_NEW_KEYWORD(SQL_TOKEN_KEY); } + +LAG {SQL_NEW_KEYWORD(SQL_TOKEN_LAG); } +LARGE {SQL_NEW_KEYWORD(SQL_TOKEN_LARGE); } +LAST {SQL_NEW_KEYWORD(SQL_TOKEN_LAST); } +LAST_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_LAST_VALUE); } +LCASE {SQL_NEW_KEYWORD(SQL_TOKEN_LCASE); } +LEAD {SQL_NEW_KEYWORD(SQL_TOKEN_LEAD); } +LEADING {SQL_NEW_KEYWORD(SQL_TOKEN_LEADING); } +LEFT {SQL_NEW_KEYWORD(SQL_TOKEN_LEFT); } +LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_LENGTH); } +LIKE {SQL_NEW_KEYWORD(SQL_TOKEN_LIKE); } +LIMIT {SQL_NEW_KEYWORD(SQL_TOKEN_LIMIT); } +LN {SQL_NEW_KEYWORD(SQL_TOKEN_LN); } +LOCAL {SQL_NEW_KEYWORD(SQL_TOKEN_LOCAL); } +LOCATE {SQL_NEW_KEYWORD(SQL_TOKEN_LOCATE); } +LOG {SQL_NEW_KEYWORD(SQL_TOKEN_LOG); } +LOGF {SQL_NEW_KEYWORD(SQL_TOKEN_LOGF); } +LOG10 {SQL_NEW_KEYWORD(SQL_TOKEN_LOG10); } +LOWER {SQL_NEW_KEYWORD(SQL_TOKEN_LOWER); } +LTRIM {SQL_NEW_KEYWORD(SQL_TOKEN_LTRIM); } + +MAX {SQL_NEW_KEYWORD(SQL_TOKEN_MAX); } +MILLISECOND {SQL_NEW_KEYWORD(SQL_TOKEN_MILLISECOND); } +MIN {SQL_NEW_KEYWORD(SQL_TOKEN_MIN); } +MINUTE {SQL_NEW_KEYWORD(SQL_TOKEN_MINUTE); } +MOD {SQL_NEW_KEYWORD(SQL_TOKEN_MOD); } +MONTH {SQL_NEW_KEYWORD(SQL_TOKEN_MONTH); } +MONTHNAME {SQL_NEW_KEYWORD(SQL_TOKEN_MONTHNAME); } + +NATIONAL {SQL_NEW_KEYWORD(SQL_TOKEN_NATIONAL); } +NATURAL {SQL_NEW_KEYWORD(SQL_TOKEN_NATURAL); } +NCHAR {SQL_NEW_KEYWORD(SQL_TOKEN_NCHAR); } +NCLOB {SQL_NEW_KEYWORD(SQL_TOKEN_NCLOB); } +NEW {SQL_NEW_KEYWORD(SQL_TOKEN_NEW); } +NEXT {SQL_NEW_KEYWORD(SQL_TOKEN_NEXT); } +NO {SQL_NEW_KEYWORD(SQL_TOKEN_NO); } +NOT {SQL_NEW_KEYWORD(SQL_TOKEN_NOT); } +NOW {SQL_NEW_KEYWORD(SQL_TOKEN_NOW); } +NTH_VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_NTH_VALUE); } +NTILE {SQL_NEW_KEYWORD(SQL_TOKEN_NTILE); } +NULL {SQL_NEW_KEYWORD(SQL_TOKEN_NULL); } +NULLIF {SQL_NEW_KEYWORD(SQL_TOKEN_NULLIF); } +NULLS {SQL_NEW_KEYWORD(SQL_TOKEN_NULLS); } +NUMERIC {SQL_NEW_KEYWORD(SQL_TOKEN_NUMERIC); } + +OBJECT {SQL_NEW_KEYWORD(SQL_TOKEN_OBJECT); } +OCTET_LENGTH {SQL_NEW_KEYWORD(SQL_TOKEN_OCTET_LENGTH); } +OF {SQL_NEW_KEYWORD(SQL_TOKEN_OF); } +OFFSET {SQL_NEW_KEYWORD(SQL_TOKEN_OFFSET); } +OJ {SQL_NEW_KEYWORD(SQL_TOKEN_OJ); } +OLD {SQL_NEW_KEYWORD(SQL_TOKEN_OLD); } +ON {SQL_NEW_KEYWORD(SQL_TOKEN_ON); } +ONLY {SQL_NEW_KEYWORD(SQL_TOKEN_ONLY); } +OPTION {SQL_NEW_KEYWORD(SQL_TOKEN_OPTION); } +OR {SQL_NEW_KEYWORD(SQL_TOKEN_OR); } +ORDER {SQL_NEW_KEYWORD(SQL_TOKEN_ORDER); } +OTHERS {SQL_NEW_KEYWORD(SQL_TOKEN_OTHERS); } +OUTER {SQL_NEW_KEYWORD(SQL_TOKEN_OUTER); } +OVER {SQL_NEW_KEYWORD(SQL_TOKEN_OVER); } + +PARTITION {SQL_NEW_KEYWORD(SQL_TOKEN_PARTITION); } +PERCENT_RANK {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENT_RANK); } +PERCENTILE_CONT {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENTILE_CONT); } +PERCENTILE_DISC {SQL_NEW_KEYWORD(SQL_TOKEN_PERCENTILE_DISC); } +PI {SQL_NEW_KEYWORD(SQL_TOKEN_PI); } +POSITION {SQL_NEW_KEYWORD(SQL_TOKEN_POSITION); } +POWER {SQL_NEW_KEYWORD(SQL_TOKEN_POWER); } +PRECEDING {SQL_NEW_KEYWORD(SQL_TOKEN_PRECEDING); } +PRECISION {SQL_NEW_KEYWORD(SQL_TOKEN_PRECISION); } +PRIMARY {SQL_NEW_KEYWORD(SQL_TOKEN_PRIMARY); } +PRIVILEGES {SQL_NEW_KEYWORD(SQL_TOKEN_PRIVILEGES); } +PROCEDURE {SQL_NEW_KEYWORD(SQL_TOKEN_PROCEDURE); } +PUBLIC {SQL_NEW_KEYWORD(SQL_TOKEN_PUBLIC); } + +QUARTER {SQL_NEW_KEYWORD(SQL_TOKEN_QUARTER); } + +RADIANS {SQL_NEW_KEYWORD(SQL_TOKEN_RADIANS); } +RAND {SQL_NEW_KEYWORD(SQL_TOKEN_RAND); } +RANGE {SQL_NEW_KEYWORD(SQL_TOKEN_RANGE); } +RANK {SQL_NEW_KEYWORD(SQL_TOKEN_RANK); } +REAL {SQL_NEW_KEYWORD(SQL_TOKEN_REAL); } +REFERENCES {SQL_NEW_KEYWORD(SQL_TOKEN_REFERENCES); } +REFERENCING {SQL_NEW_KEYWORD(SQL_TOKEN_REFERENCING); } +REPEAT {SQL_NEW_KEYWORD(SQL_TOKEN_REPEAT); } +REPLACE {SQL_NEW_KEYWORD(SQL_TOKEN_REPLACE); } +RESPECT {SQL_NEW_KEYWORD(SQL_TOKEN_RESPECT); } +ROLLBACK {SQL_NEW_KEYWORD(SQL_TOKEN_ROLLBACK); } +ROUND {SQL_NEW_KEYWORD(SQL_TOKEN_ROUND); } +ROUNDMAGIC {SQL_NEW_KEYWORD(SQL_TOKEN_ROUNDMAGIC); } +ROW {SQL_NEW_KEYWORD(SQL_TOKEN_ROW); } +ROWS {SQL_NEW_KEYWORD(SQL_TOKEN_ROWS); } +ROW_NUMBER {SQL_NEW_KEYWORD(SQL_TOKEN_ROW_NUMBER); } +RIGHT {SQL_NEW_KEYWORD(SQL_TOKEN_RIGHT); } +RTRIM {SQL_NEW_KEYWORD(SQL_TOKEN_RTRIM); } + +SCHEMA {SQL_NEW_KEYWORD(SQL_TOKEN_SCHEMA); } +SECOND {SQL_NEW_KEYWORD(SQL_TOKEN_SECOND); } +SELECT {SQL_NEW_KEYWORD(SQL_TOKEN_SELECT); } +SET {SQL_NEW_KEYWORD(SQL_TOKEN_SET); } +SIZE {SQL_NEW_KEYWORD(SQL_TOKEN_SIZE); } +SIGN {SQL_NEW_KEYWORD(SQL_TOKEN_SIGN); } +SIN {SQL_NEW_KEYWORD(SQL_TOKEN_SIN); } +SMALLINT {SQL_NEW_KEYWORD(SQL_TOKEN_SMALLINT); } +SOME {SQL_NEW_KEYWORD(SQL_TOKEN_SOME); } +SOUNDEX {SQL_NEW_KEYWORD(SQL_TOKEN_SOUNDEX); } +SPACE {SQL_NEW_KEYWORD(SQL_TOKEN_SPACE); } +SQRT {SQL_NEW_KEYWORD(SQL_TOKEN_SQRT); } +STDDEV_POP {SQL_NEW_KEYWORD(SQL_TOKEN_STDDEV_POP); } +STDDEV_SAMP {SQL_NEW_KEYWORD(SQL_TOKEN_STDDEV_SAMP); } +STATEMENT {SQL_NEW_KEYWORD(SQL_TOKEN_STATEMENT); } +SUBSTRING {SQL_NEW_KEYWORD(SQL_TOKEN_SUBSTRING); } +SUM {SQL_NEW_KEYWORD(SQL_TOKEN_SUM); } +SESSION_USER {SQL_NEW_KEYWORD(SQL_TOKEN_SESSION_USER); } +SYSTEM_USER {SQL_NEW_KEYWORD(SQL_TOKEN_SYSTEM_USER); } + +TABLE {SQL_NEW_KEYWORD(SQL_TOKEN_TABLE); } +TAN {SQL_NEW_KEYWORD(SQL_TOKEN_TAN); } +THEN {SQL_NEW_KEYWORD(SQL_TOKEN_THEN); } +TIES {SQL_NEW_KEYWORD(SQL_TOKEN_TIES); } +TIME {SQL_NEW_KEYWORD(SQL_TOKEN_TIME); } +TIMESTAMP {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMP); } +TIMESTAMPADD {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMPADD); } +TIMESTAMPDIFF {SQL_NEW_KEYWORD(SQL_TOKEN_TIMESTAMPDIFF); } +TIMEVALUE {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEVALUE); } +TIMEZONE_HOUR {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEZONE_HOUR); } +TIMEZONE_MINUTE {SQL_NEW_KEYWORD(SQL_TOKEN_TIMEZONE_MINUTE); } +TO {SQL_NEW_KEYWORD(SQL_TOKEN_TO); } +TRAILING {SQL_NEW_KEYWORD(SQL_TOKEN_TRAILING); } +TRANSLATE {SQL_NEW_KEYWORD(SQL_TOKEN_TRANSLATE); } +TRIGGER {SQL_NEW_KEYWORD(SQL_TOKEN_TRIGGER); } +TRIM {SQL_NEW_KEYWORD(SQL_TOKEN_TRIM); } +TRUE {SQL_NEW_KEYWORD(SQL_TOKEN_TRUE); } +TRUNCATE {SQL_NEW_KEYWORD(SQL_TOKEN_TRUNCATE); } +TS {SQL_NEW_KEYWORD(SQL_TOKEN_TS); } +T {SQL_NEW_KEYWORD(SQL_TOKEN_T); } + +UCASE {SQL_NEW_KEYWORD(SQL_TOKEN_UCASE); } +UNBOUNDED {SQL_NEW_KEYWORD(SQL_TOKEN_UNBOUNDED); } +UNION {SQL_NEW_KEYWORD(SQL_TOKEN_UNION); } +UNIQUE {SQL_NEW_KEYWORD(SQL_TOKEN_UNIQUE); } +UNKNOWN {SQL_NEW_KEYWORD(SQL_TOKEN_UNKNOWN); } +UPDATE {SQL_NEW_KEYWORD(SQL_TOKEN_UPDATE); } +UPPER {SQL_NEW_KEYWORD(SQL_TOKEN_UPPER); } +USAGE {SQL_NEW_KEYWORD(SQL_TOKEN_USAGE); } +USER {SQL_NEW_KEYWORD(SQL_TOKEN_USER); } +USING {SQL_NEW_KEYWORD(SQL_TOKEN_USING); } + +VARBINARY {SQL_NEW_KEYWORD(SQL_TOKEN_VARBINARY); } +VARCHAR {SQL_NEW_KEYWORD(SQL_TOKEN_VARCHAR); } +VARYING {SQL_NEW_KEYWORD(SQL_TOKEN_VARYING); } +VAR_POP {SQL_NEW_KEYWORD(SQL_TOKEN_VAR_POP); } +VAR_SAMP {SQL_NEW_KEYWORD(SQL_TOKEN_VAR_SAMP); } +VALUE {SQL_NEW_KEYWORD(SQL_TOKEN_VALUE); } +VALUES {SQL_NEW_KEYWORD(SQL_TOKEN_VALUES); } +VIEW {SQL_NEW_KEYWORD(SQL_TOKEN_VIEW); } + +WEEK {SQL_NEW_KEYWORD(SQL_TOKEN_WEEK); } +WEEKDAY {SQL_NEW_KEYWORD(SQL_TOKEN_WEEKDAY); } +WHEN {SQL_NEW_KEYWORD(SQL_TOKEN_WHEN); } +WHERE {SQL_NEW_KEYWORD(SQL_TOKEN_WHERE); } +WITH {SQL_NEW_KEYWORD(SQL_TOKEN_WITH); } +WITHIN {SQL_NEW_KEYWORD(SQL_TOKEN_WITHIN); } +WITHOUT {SQL_NEW_KEYWORD(SQL_TOKEN_WITHOUT); } +WORK {SQL_NEW_KEYWORD(SQL_TOKEN_WORK); } + +YEAR {SQL_NEW_KEYWORD(SQL_TOKEN_YEAR); } +YEARDAY {SQL_NEW_KEYWORD(SQL_TOKEN_YEARDAY); } + +ZONE {SQL_NEW_KEYWORD(SQL_TOKEN_ZONE); } + +"<" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Less);return SQL_LESS;} +">" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Great);return SQL_GREAT;} +"=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Equal);return SQL_EQUAL;} +"<=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::LessEq);return SQL_LESSEQ;} +">=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::GreatEq);return SQL_GREATEQ;} +"<>" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::NotEqual);return SQL_NOTEQUAL;} +"!=" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::NotEqual);return SQL_NOTEQUAL;} +"||" { SQL_NEW_NODE(OUString(SQLyytext,strlen(SQLyytext),RTL_TEXTENCODING_UTF8), SQLNodeType::Concat);return SQL_CONCAT;} + + +[-+*/:(),.;?{}] { return SQLyytext[0]; } + + +<SQL>[A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375][A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375_0-9]* {return gatherName( SQLyytext);} + +<SQL>([0-9]+) {SQL_NEW_INTNUM; } + +<SQL>("."[0-9]*) | +<SQL>([0-9]+"."[0-9]*) | +<SQL>[0-9]+[eE][+-]?[0-9]+ | +<SQL>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ | +<SQL>"."[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; } + +<PREDICATE_GER,PREDICATE_ENG,DATE>[A-Za-z\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375][A-Za-z0-9_%.,*?\200-\277\300-\337\340-\357\360-\367\370-\373\374-\375]* {return gatherNamePre(SQLyytext);} + +<PREDICATE_GER,PREDICATE_ENG>([0-9]+) {SQL_NEW_INTNUM; } +<PREDICATE_ENG>([0-9]{1,3}(","[0-9]{3})+) {SQL_NEW_INTNUM; } +<PREDICATE_GER>([0-9]{1,3}("."[0-9]{3})+) {SQL_NEW_INTNUM; } + +<PREDICATE_ENG>([0-9]+"."[0-9]+) | +<PREDICATE_ENG>([0-9]{1,3}(","[0-9]{3})+"."[0-9]+) | +<PREDICATE_ENG>("."[0-9]+) {SQL_NEW_APPROXNUM; } +<PREDICATE_ENG>[0-9]+[eE][+-]?[0-9]+ | +<PREDICATE_ENG>[0-9]+"."[0-9]*[eE][+-]?[0-9]+ | +<PREDICATE_ENG>"."[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; } + +<PREDICATE_GER>([0-9]+","[0-9]+) | +<PREDICATE_GER>([0-9]{1,3}("."[0-9]{3})+","[0-9]+) | +<PREDICATE_GER>(","[0-9]+) {SQL_NEW_APPROXNUM; } +<PREDICATE_GER>[0-9]+[eE][+-]?[0-9]+ | +<PREDICATE_GER>[0-9]+","[0-9]*[eE][+-]?[0-9]+ | +<PREDICATE_GER>","[0-9]*[eE][+-]?[0-9]+ {SQL_NEW_APPROXNUM; } + +<PREDICATE_GER,PREDICATE_ENG>[0-9.,][A-Za-z0-9_.,%]* {return gatherNamePre(SQLyytext);} + +<SQL>\" { return gatherString('\"',0); } +<SQL>` { return gatherString('`' ,0); } + +<PREDICATE_GER,PREDICATE_ENG,DATE,SQL>"[" { return gatherString(']' ,0);} + +\' { return gatherString('\'',1); } + +<PREDICATE_GER,PREDICATE_ENG,DATE># { return gatherString('#' ,2); } + +<DATE>[0-9]{1,4}[^ ]*[0-9] | +<DATE>[0-9]{1,4}[^ ]*[0-9][ ][0-9]{1,4}[^ ]*[0-9] { SQL_NEW_DATE; } + +<STRING>["-""+""*""/"":""("")"",""."";""?""{""}"] { return SQLyytext[0]; } /* */ +<STRING>"[" { return gatherString(']' ,0); } +<STRING>[^ ':["?"]* { return gatherNamePre(SQLyytext); } + +\n {} + +[ \t\r]+ {} + +"--".*$ {} + +. {YY_FATAL_ERROR("Invalid symbol"); return SQL_TOKEN_INVALIDSYMBOL;} + +%% + +// Kludge around a bug (well, Posix incompatibility) in flex 2.5.x +// http://bugs.debian.org/cgi-bin/bugreport.cgi?archive=no&bug=189332 +#if YY_FLEX_MAJOR_VERSION >= 2 && YY_FLEX_MINOR_VERSION >= 5 + + #ifndef YY_FLUSH_BUFFER + #define YY_FLUSH_BUFFER SQLyy_flush_buffer(YY_CURRENT_BUFFER ) + #endif + + #ifndef yytext_ptr + #define yytext_ptr SQLyytext + #endif + +#endif + +// Versions of flex apparently differ in whether input() resp. yyinput() returns +// zero or EOF upon end of file: +inline bool checkeof(int c) { return c == 0 || c == EOF; } + +/* + * Read SQL string literal + * Valid strings: + * '' 'a string' 'quote '' within string' + * "" "a string" "quote "" within string" + * nTyp == 0 -> SQLNodeType::Name + * nTyp == 1 -> SQLNodeType::String + * nTyp == 2 -> SQLNodeType::AccessDate + */ +sal_Int32 gatherString(int delim, sal_Int32 nTyp) +{ + int ch; + OStringBuffer sBuffer(256); + + assert(nTyp == 0 || nTyp == 1 || nTyp == 2); + + while (!checkeof(ch = yyinput())) + { + if (ch == delim) + { + if ((ch = yyinput()) != delim) + { + if (!checkeof(ch)) + unput(ch); + + switch(nTyp) + { + case 0: + SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::Name); + return SQL_TOKEN_NAME; + case 1: + SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::String); + return SQL_TOKEN_STRING; + case 2: + SQL_NEW_NODE(OStringToOUString(sBuffer.makeStringAndClear(),RTL_TEXTENCODING_UTF8), SQLNodeType::AccessDate); + return SQL_TOKEN_ACCESS_DATE; + } + } + else + { + sBuffer.append(static_cast<char>(ch)); + } + + } + else if (nTyp == 2 && (ch == '\r' || ch == '\n') ) + break; + else + { + sBuffer.append(static_cast<char>(ch)); + } + } + YY_FATAL_ERROR("Unterminated name string"); + return SQL_TOKEN_INVALIDSYMBOL; +} + +sal_Int32 mapEnumToToken(IParseContext::InternationalKeyCode _eKeyCode ) +{ + sal_Int32 nTokenID = 0; + switch( _eKeyCode ) + { + case IParseContext::InternationalKeyCode::Like: nTokenID = SQL_TOKEN_LIKE; break; + case IParseContext::InternationalKeyCode::Not: nTokenID = SQL_TOKEN_NOT; break; + case IParseContext::InternationalKeyCode::Null: nTokenID = SQL_TOKEN_NULL; break; + case IParseContext::InternationalKeyCode::True: nTokenID = SQL_TOKEN_TRUE; break; + case IParseContext::InternationalKeyCode::False: nTokenID = SQL_TOKEN_FALSE; break; + case IParseContext::InternationalKeyCode::Is: nTokenID = SQL_TOKEN_IS; break; + case IParseContext::InternationalKeyCode::Between: nTokenID = SQL_TOKEN_BETWEEN; break; + case IParseContext::InternationalKeyCode::Or: nTokenID = SQL_TOKEN_OR; break; + case IParseContext::InternationalKeyCode::And: nTokenID = SQL_TOKEN_AND; break; + case IParseContext::InternationalKeyCode::Avg: nTokenID = SQL_TOKEN_AVG; break; + case IParseContext::InternationalKeyCode::Count: nTokenID = SQL_TOKEN_COUNT; break; + case IParseContext::InternationalKeyCode::Max: nTokenID = SQL_TOKEN_MAX; break; + case IParseContext::InternationalKeyCode::Min: nTokenID = SQL_TOKEN_MIN; break; + case IParseContext::InternationalKeyCode::Sum: nTokenID = SQL_TOKEN_SUM; break; + case IParseContext::InternationalKeyCode::Every: nTokenID = SQL_TOKEN_EVERY; break; + case IParseContext::InternationalKeyCode::Any: nTokenID = SQL_TOKEN_ANY; break; + case IParseContext::InternationalKeyCode::Some: nTokenID = SQL_TOKEN_SOME; break; + case IParseContext::InternationalKeyCode::StdDevPop: nTokenID = SQL_TOKEN_STDDEV_POP; break; + case IParseContext::InternationalKeyCode::StdDevSamp: nTokenID = SQL_TOKEN_STDDEV_SAMP; break; + case IParseContext::InternationalKeyCode::VarSamp: nTokenID = SQL_TOKEN_VAR_SAMP; break; + case IParseContext::InternationalKeyCode::VarPop: nTokenID = SQL_TOKEN_VAR_POP; break; + case IParseContext::InternationalKeyCode::Collect: nTokenID = SQL_TOKEN_COLLECT; break; + case IParseContext::InternationalKeyCode::Fusion: nTokenID = SQL_TOKEN_FUSION; break; + case IParseContext::InternationalKeyCode::Intersection: nTokenID = SQL_TOKEN_INTERSECTION; break; + default: + OSL_FAIL( "mapEnumToToken: unsupported key!" ); + } + return nTokenID; +} +/* + * Read SQL Name literal + * Valid Names or international keywords: + * As we have international keywords, we test first on them + */ +sal_Int32 gatherName(const char* text) +{ + sal_Int32 nToken; + OSL_ENSURE(xxx_pGLOBAL_SQLSCAN,"You forgot to set the scanner!"); + IParseContext::InternationalKeyCode eKeyCode = xxx_pGLOBAL_SQLSCAN->getInternationalTokenID(text); + switch (eKeyCode) + { + case IParseContext::InternationalKeyCode::Like: + case IParseContext::InternationalKeyCode::Not: + case IParseContext::InternationalKeyCode::Null: + case IParseContext::InternationalKeyCode::True: + case IParseContext::InternationalKeyCode::False: + case IParseContext::InternationalKeyCode::Is: + case IParseContext::InternationalKeyCode::Between: + case IParseContext::InternationalKeyCode::Or: + case IParseContext::InternationalKeyCode::And: + case IParseContext::InternationalKeyCode::Count: + case IParseContext::InternationalKeyCode::Avg: + case IParseContext::InternationalKeyCode::Max: + case IParseContext::InternationalKeyCode::Min: + case IParseContext::InternationalKeyCode::Sum: + case IParseContext::InternationalKeyCode::Every: + case IParseContext::InternationalKeyCode::Any: + case IParseContext::InternationalKeyCode::Some: + case IParseContext::InternationalKeyCode::StdDevPop: + case IParseContext::InternationalKeyCode::StdDevSamp: + case IParseContext::InternationalKeyCode::VarSamp: + case IParseContext::InternationalKeyCode::VarPop: + case IParseContext::InternationalKeyCode::Collect: + case IParseContext::InternationalKeyCode::Fusion: + case IParseContext::InternationalKeyCode::Intersection: + nToken = mapEnumToToken(eKeyCode); + SQL_NEW_KEYWORD(nToken); + break; + default: + SQL_NEW_NODE(OUString(text,strlen(text),RTL_TEXTENCODING_UTF8), SQLNodeType::Name); + return SQL_TOKEN_NAME; + } +} +/** + Read SQL Name literal for predicate check + Valid Names or international keywords: + As we have international keywords, we test first on them +*/ +sal_Int32 gatherNamePre(const char* text) +{ + sal_Int32 nToken; + OSL_ENSURE(xxx_pGLOBAL_SQLSCAN,"You forgot to set the scanner!"); + IParseContext::InternationalKeyCode eKeyCode = xxx_pGLOBAL_SQLSCAN->getInternationalTokenID(text); + switch (eKeyCode) + { + case IParseContext::InternationalKeyCode::Like: + case IParseContext::InternationalKeyCode::Not: + case IParseContext::InternationalKeyCode::Null: + case IParseContext::InternationalKeyCode::True: + case IParseContext::InternationalKeyCode::False: + case IParseContext::InternationalKeyCode::Is: + case IParseContext::InternationalKeyCode::Between: + case IParseContext::InternationalKeyCode::Or: + case IParseContext::InternationalKeyCode::And: + case IParseContext::InternationalKeyCode::Count: + case IParseContext::InternationalKeyCode::Avg: + case IParseContext::InternationalKeyCode::Max: + case IParseContext::InternationalKeyCode::Min: + case IParseContext::InternationalKeyCode::Sum: + case IParseContext::InternationalKeyCode::Every: + case IParseContext::InternationalKeyCode::Any: + case IParseContext::InternationalKeyCode::Some: + case IParseContext::InternationalKeyCode::StdDevPop: + case IParseContext::InternationalKeyCode::StdDevSamp: + case IParseContext::InternationalKeyCode::VarSamp: + case IParseContext::InternationalKeyCode::VarPop: + case IParseContext::InternationalKeyCode::Collect: + case IParseContext::InternationalKeyCode::Fusion: + case IParseContext::InternationalKeyCode::Intersection: + nToken = mapEnumToToken(eKeyCode); + SQL_NEW_KEYWORD(nToken); + break; + default: + // we need a special handling for parameter + { + OString sStmt = xxx_pGLOBAL_SQLSCAN->getStatement(); + sal_Int32 nLength = strlen(text); + sal_Int32 nPos = xxx_pGLOBAL_SQLSCAN->GetCurrentPos() - nLength - 2; + if (sStmt.getStr()[nPos] == ':') + { + SQL_NEW_NODE(OUString(text,nLength,RTL_TEXTENCODING_UTF8), SQLNodeType::Name); + nToken = SQL_TOKEN_NAME; + } + else + { + SQL_NEW_NODE(OUString(text,nLength,RTL_TEXTENCODING_UTF8), SQLNodeType::String); + nToken = SQL_TOKEN_STRING; + } + } + } + return nToken; +} + +using namespace connectivity; + +static bool IN_SQLyyerror; +//------------------------------------------------------------------------------ +OSQLScanner::OSQLScanner() + : m_pContext(nullptr) + , m_nCurrentPos(0) + , m_bInternational(false) + , m_nRule(0) // 0 is INITIAL +{ + IN_SQLyyerror = false; +} + +//------------------------------------------------------------------------------ +OSQLScanner::~OSQLScanner() +{ +} +//------------------------------------------------------------------------------ +void OSQLScanner::SQLyyerror(char const *fmt) +{ + + if(IN_SQLyyerror) + return; + IN_SQLyyerror = true; + + OSL_ENSURE(m_pContext, "OSQLScanner::SQLyyerror: No Context set"); + m_sErrorMessage = OUString(fmt,strlen(fmt),RTL_TEXTENCODING_UTF8); + if (m_nCurrentPos < m_sStatement.getLength()) + { + m_sErrorMessage += ": "; + + OUString aError; + OUStringBuffer Buffer(256); + + int ch = SQLyytext ? (SQLyytext[0] == 0 ? ' ' : SQLyytext[0]): ' '; + Buffer.append((sal_Unicode)ch); + while (!checkeof(ch = yyinput())) + { + if (ch == ' ') + { + if ((ch = yyinput()) != ' ') + { + if (!checkeof(ch)) + unput(ch); + } + aError = Buffer.makeStringAndClear(); + break; + } + else + { + Buffer.append((sal_Unicode)ch); + } + } + m_sErrorMessage += aError; + } + IN_SQLyyerror = false; + YY_FLUSH_BUFFER; +} + +//------------------------------------------------------------------------------ +void OSQLScanner::prepareScan(const OUString & rNewStatement, const IParseContext* pContext, bool bInternational) +{ + YY_FLUSH_BUFFER; + BEGIN(m_nRule); + + m_sErrorMessage = OUString(); + m_sStatement = OUStringToOString(rNewStatement, RTL_TEXTENCODING_UTF8); + m_nCurrentPos = 0; + m_bInternational = bInternational; + m_pContext = pContext; +} + +//------------------------------------------------------------------------------ +sal_Int32 OSQLScanner::SQLyygetc(void) +{ + sal_Int32 nPos = (m_nCurrentPos >= m_sStatement.getLength()) ? EOF : m_sStatement.getStr()[m_nCurrentPos]; + m_nCurrentPos++; + return nPos; +} + +//------------------------------------------------------------------------------ +IParseContext::InternationalKeyCode OSQLScanner::getInternationalTokenID(const char* sToken) const +{ + OSL_ENSURE(m_pContext, "OSQLScanner::getInternationalTokenID: No Context set"); + return (m_bInternational) ? m_pContext->getIntlKeyCode(OString(sToken) ) : IParseContext::InternationalKeyCode::None; +} +sal_Int32 OSQLScanner::GetGERRule() { return PREDICATE_GER; } +sal_Int32 OSQLScanner::GetENGRule() { return PREDICATE_ENG; } +sal_Int32 OSQLScanner::GetSQLRule() { return SQL; } +sal_Int32 OSQLScanner::GetDATERule() { return DATE; } +sal_Int32 OSQLScanner::GetSTRINGRule() { return STRING; } +void OSQLScanner::setScanner(bool _bNull) +{ + xxx_pGLOBAL_SQLSCAN = _bNull ? nullptr : this; +} +sal_Int32 OSQLScanner::SQLlex() +{ + return SQLyylex(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/connectivity/source/parse/sqliterator.cxx b/connectivity/source/parse/sqliterator.cxx new file mode 100644 index 000000000..d8c48c643 --- /dev/null +++ b/connectivity/source/parse/sqliterator.cxx @@ -0,0 +1,2102 @@ +/* -*- 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/sqliterator.hxx> +#include <connectivity/sdbcx/VTable.hxx> +#include <connectivity/sqlparse.hxx> +#include <sqlbison.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/sqlerror.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#ifdef SQL_TEST_PARSETREEITERATOR +#include <iostream> +#endif +#include <connectivity/PColumn.hxx> +#include <tools/diagnose_ex.h> +#include <TConnection.hxx> +#include <comphelper/types.hxx> +#include <connectivity/dbmetadata.hxx> +#include <com/sun/star/sdb/SQLFilterOperator.hpp> +#include <sal/log.hxx> + +#include <iterator> +#include <memory> + +using namespace ::comphelper; +using namespace ::connectivity; +using namespace ::connectivity::sdbcx; +using namespace ::dbtools; +using namespace ::connectivity::parse; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdb; + +namespace connectivity +{ + struct OSQLParseTreeIteratorImpl + { + std::vector< TNodePair > m_aJoinConditions; + Reference< XConnection > m_xConnection; + Reference< XDatabaseMetaData > m_xDatabaseMetaData; + Reference< XNameAccess > m_xTableContainer; + Reference< XNameAccess > m_xQueryContainer; + + std::shared_ptr< OSQLTables > m_pTables; // all tables which participate in the SQL statement + std::shared_ptr< OSQLTables > m_pSubTables; // all tables from sub queries not the tables from the select tables + std::shared_ptr< QueryNameSet > m_pForbiddenQueryNames; + + TraversalParts m_nIncludeMask; + + bool m_bIsCaseSensitive; + + OSQLParseTreeIteratorImpl( const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxTables ) + :m_xConnection( _rxConnection ) + ,m_nIncludeMask( TraversalParts::All ) + ,m_bIsCaseSensitive( true ) + { + OSL_PRECOND( m_xConnection.is(), "OSQLParseTreeIteratorImpl::OSQLParseTreeIteratorImpl: invalid connection!" ); + m_xDatabaseMetaData = m_xConnection->getMetaData(); + + m_bIsCaseSensitive = m_xDatabaseMetaData.is() && m_xDatabaseMetaData->supportsMixedCaseQuotedIdentifiers(); + m_pTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive ); + m_pSubTables = std::make_shared<OSQLTables>( m_bIsCaseSensitive ); + + m_xTableContainer = _rxTables; + + DatabaseMetaData aMetaData( m_xConnection ); + if ( aMetaData.supportsSubqueriesInFrom() ) + { + // connections might support the XQueriesSupplier interface, if they implement the css.sdb.Connection + // service + Reference< XQueriesSupplier > xSuppQueries( m_xConnection, UNO_QUERY ); + if ( xSuppQueries.is() ) + m_xQueryContainer = xSuppQueries->getQueries(); + } + } + + public: + bool isQueryAllowed( const OUString& _rQueryName ) + { + if ( !m_pForbiddenQueryNames ) + return true; + if ( m_pForbiddenQueryNames->find( _rQueryName ) == m_pForbiddenQueryNames->end() ) + return true; + return false; + } + }; + + namespace { + + /** helper class for temporarily adding a query name to a list of forbidden query names + */ + class ForbidQueryName + { + std::shared_ptr< QueryNameSet >& m_rpAllForbiddenNames; + OUString m_sForbiddenQueryName; + + public: + ForbidQueryName( OSQLParseTreeIteratorImpl& _rIteratorImpl, const OUString& _rForbiddenQueryName ) + :m_rpAllForbiddenNames( _rIteratorImpl.m_pForbiddenQueryNames ) + ,m_sForbiddenQueryName( _rForbiddenQueryName ) + { + if ( !m_rpAllForbiddenNames ) + m_rpAllForbiddenNames = std::make_shared<QueryNameSet>(); + m_rpAllForbiddenNames->insert( m_sForbiddenQueryName ); + } + + ~ForbidQueryName() + { + m_rpAllForbiddenNames->erase( m_sForbiddenQueryName ); + } + }; + + } +} + +OSQLParseTreeIterator::OSQLParseTreeIterator(const Reference< XConnection >& _rxConnection, + const Reference< XNameAccess >& _rxTables, + const OSQLParser& _rParser ) + :m_rParser( _rParser ) + ,m_pImpl( new OSQLParseTreeIteratorImpl( _rxConnection, _rxTables ) ) +{ + setParseTree(nullptr); +} + + +OSQLParseTreeIterator::OSQLParseTreeIterator( const OSQLParseTreeIterator& _rParentIterator, const OSQLParser& _rParser, const OSQLParseNode* pRoot ) + :m_rParser( _rParser ) + ,m_pImpl( new OSQLParseTreeIteratorImpl( _rParentIterator.m_pImpl->m_xConnection, _rParentIterator.m_pImpl->m_xTableContainer ) ) +{ + m_pImpl->m_pForbiddenQueryNames = _rParentIterator.m_pImpl->m_pForbiddenQueryNames; + setParseTree( pRoot ); +} + + +OSQLParseTreeIterator::~OSQLParseTreeIterator() +{ + dispose(); +} + + +const OSQLTables& OSQLParseTreeIterator::getTables() const +{ + return *m_pImpl->m_pTables; +} + + +bool OSQLParseTreeIterator::isCaseSensitive() const +{ + return m_pImpl->m_bIsCaseSensitive; +} + + +void OSQLParseTreeIterator::dispose() +{ + m_aSelectColumns = nullptr; + m_aGroupColumns = nullptr; + m_aOrderColumns = nullptr; + m_aParameters = nullptr; + m_pImpl->m_xTableContainer = nullptr; + m_pImpl->m_xDatabaseMetaData = nullptr; + m_aCreateColumns = nullptr; + m_pImpl->m_pTables->clear(); + m_pImpl->m_pSubTables->clear(); +} + +void OSQLParseTreeIterator::setParseTree(const OSQLParseNode * pNewParseTree) +{ + m_pImpl->m_pTables->clear(); + m_pImpl->m_pSubTables->clear(); + + m_aSelectColumns = new OSQLColumns(); + m_aGroupColumns = new OSQLColumns(); + m_aOrderColumns = new OSQLColumns(); + m_aParameters = new OSQLColumns(); + m_aCreateColumns = new OSQLColumns(); + + m_pParseTree = pNewParseTree; + if (!m_pParseTree) + { + m_eStatementType = OSQLStatementType::Unknown; + return; + } + + // If m_pParseTree, but no connection then return + if ( !m_pImpl->m_xTableContainer.is() ) + return; + + m_xErrors.reset(); + + + // Determine statement type ... + if (SQL_ISRULE(m_pParseTree,select_statement) || SQL_ISRULE(m_pParseTree,union_statement) ) + { + m_eStatementType = OSQLStatementType::Select; + } + else if (SQL_ISRULE(m_pParseTree,insert_statement)) + { + m_eStatementType = OSQLStatementType::Insert; + } + else if (SQL_ISRULE(m_pParseTree,update_statement_searched)) + { + m_eStatementType = OSQLStatementType::Update; + } + else if (SQL_ISRULE(m_pParseTree,delete_statement_searched)) + { + m_eStatementType = OSQLStatementType::Delete; + } + else if (m_pParseTree->count() == 3 && SQL_ISRULE(m_pParseTree->getChild(1),odbc_call_spec)) + { + m_eStatementType = OSQLStatementType::OdbcCall; + } + else if (SQL_ISRULE(m_pParseTree->getChild(0),base_table_def)) + { + m_eStatementType = OSQLStatementType::CreateTable; + m_pParseTree = m_pParseTree->getChild(0); + } + else + { + m_eStatementType = OSQLStatementType::Unknown; + //aIteratorStatus.setInvalidStatement(); + return; + } +} + + +namespace +{ + + void impl_getRowString( const Reference< XRow >& _rxRow, const sal_Int32 _nColumnIndex, OUString& _out_rString ) + { + _out_rString = _rxRow->getString( _nColumnIndex ); + if ( _rxRow->wasNull() ) + _out_rString.clear(); + } + + + OUString lcl_findTableInMetaData( + const Reference< XDatabaseMetaData >& _rxDBMeta, const OUString& _rCatalog, + const OUString& _rSchema, const OUString& _rTableName ) + { + OUString sComposedName; + + static const char s_sWildcard[] = "%" ; + + // we want all catalogues, all schemas, all tables + Sequence< OUString > sTableTypes(3); + sTableTypes[0] = "VIEW"; + sTableTypes[1] = "TABLE"; + sTableTypes[2] = s_sWildcard; // just to be sure to include anything else... + + if ( _rxDBMeta.is() ) + { + sComposedName.clear(); + + Reference< XResultSet> xRes = _rxDBMeta->getTables( + !_rCatalog.isEmpty() ? makeAny( _rCatalog ) : Any(), !_rSchema.isEmpty() ? _rSchema : s_sWildcard, _rTableName, sTableTypes ); + + Reference< XRow > xCurrentRow( xRes, UNO_QUERY ); + if ( xCurrentRow.is() && xRes->next() ) + { + OUString sCatalog, sSchema, sName; + + impl_getRowString( xCurrentRow, 1, sCatalog ); + impl_getRowString( xCurrentRow, 2, sSchema ); + impl_getRowString( xCurrentRow, 3, sName ); + + sComposedName = ::dbtools::composeTableName( + _rxDBMeta, + sCatalog, + sSchema, + sName, + false, + ::dbtools::EComposeRule::InDataManipulation + ); + } + } + return sComposedName; + } +} + + +void OSQLParseTreeIterator::impl_getQueryParameterColumns( const OSQLTable& _rQuery ) +{ + if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) ) + // parameters not to be included in the traversal + return; + + ::rtl::Reference pSubQueryParameterColumns( new OSQLColumns() ); + + // get the command and the EscapeProcessing properties from the sub query + OUString sSubQueryCommand; + bool bEscapeProcessing = false; + try + { + Reference< XPropertySet > xQueryProperties( _rQuery, UNO_QUERY_THROW ); + OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sSubQueryCommand ); + OSL_VERIFY( xQueryProperties->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.parse"); + } + + // parse the sub query + do { + + if ( !bEscapeProcessing || ( sSubQueryCommand.isEmpty() ) ) + break; + + OUString sError; + std::unique_ptr< OSQLParseNode > pSubQueryNode( const_cast< OSQLParser& >( m_rParser ).parseTree( sError, sSubQueryCommand ) ); + if (!pSubQueryNode) + break; + + OSQLParseTreeIterator aSubQueryIterator( *this, m_rParser, pSubQueryNode.get() ); + aSubQueryIterator.impl_traverse( TraversalParts::Parameters | TraversalParts::SelectColumns ); + // SelectColumns might also contain parameters #i77635# + pSubQueryParameterColumns = aSubQueryIterator.getParameters(); + aSubQueryIterator.dispose(); + + } while ( false ); + + // copy the parameters of the sub query to our own parameter array + std::copy( pSubQueryParameterColumns->begin(), pSubQueryParameterColumns->end(), + std::back_inserter( *m_aParameters ) ); +} + + +OSQLTable OSQLParseTreeIterator::impl_locateRecordSource( const OUString& _rComposedName ) +{ + if ( _rComposedName.isEmpty() ) + { + SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::impl_locateRecordSource: no object name at all?" ); + return OSQLTable(); + } + + OSQLTable aReturn; + OUString sComposedName( _rComposedName ); + + try + { + OUString sCatalog, sSchema, sName; + qualifiedNameComponents( m_pImpl->m_xDatabaseMetaData, sComposedName, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + + // check whether there is a query with the given name + bool bQueryDoesExist = m_pImpl->m_xQueryContainer.is() && m_pImpl->m_xQueryContainer->hasByName( sComposedName ); + + // check whether the table container contains an object with the given name + if ( !bQueryDoesExist && !m_pImpl->m_xTableContainer->hasByName( sComposedName ) ) + sComposedName = lcl_findTableInMetaData( m_pImpl->m_xDatabaseMetaData, sCatalog, sSchema, sName ); + bool bTableDoesExist = m_pImpl->m_xTableContainer->hasByName( sComposedName ); + + // now obtain the object + + // if we're creating a table, and there already is a table or query with the same name, + // this is worth an error + if ( OSQLStatementType::CreateTable == m_eStatementType ) + { + if ( bQueryDoesExist ) + impl_appendError( IParseContext::ErrorCode::InvalidQueryExist, &sName ); + else if ( bTableDoesExist ) + impl_appendError( IParseContext::ErrorCode::InvalidTableExist, &sName ); + else + aReturn = impl_createTableObject( sName, sCatalog, sSchema ); + } + else + { + // queries win over tables, so if there's a query with this name, take this, no matter if + // there's a table, too + if ( bQueryDoesExist ) + { + if ( !m_pImpl->isQueryAllowed( sComposedName ) ) + { + impl_appendError( m_rParser.getErrorHelper().getSQLException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES, nullptr ) ); + return nullptr; + } + + m_pImpl->m_xQueryContainer->getByName( sComposedName ) >>= aReturn; + + // collect the parameters from the sub query + ForbidQueryName aForbidName( *m_pImpl, sComposedName ); + impl_getQueryParameterColumns( aReturn ); + } + else if ( bTableDoesExist ) + m_pImpl->m_xTableContainer->getByName( sComposedName ) >>= aReturn; + else + { + if ( m_pImpl->m_xQueryContainer.is() ) + // the connection on which we're working supports sub queries in from (else + // m_xQueryContainer would not have been set), so emit a better error message + impl_appendError( IParseContext::ErrorCode::InvalidTableOrQuery, &sName ); + else + impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sName ); + } + } + } + catch(Exception&) + { + impl_appendError( IParseContext::ErrorCode::InvalidTableNosuch, &sComposedName ); + } + + return aReturn; +} + + +void OSQLParseTreeIterator::traverseOneTableName( OSQLTables& _rTables,const OSQLParseNode * pTableName, const OUString & rTableRange ) +{ + if ( !( m_pImpl->m_nIncludeMask & TraversalParts::TableNames ) ) + // tables should not be included in the traversal + return; + + OSL_ENSURE(pTableName != nullptr,"OSQLParseTreeIterator::traverseOneTableName: pTableName == NULL"); + + Any aCatalog; + OUString aSchema,aTableName,aComposedName; + OUString aTableRange(rTableRange); + + // Get table name + OSQLParseNode::getTableComponents(pTableName,aCatalog,aSchema,aTableName,m_pImpl->m_xDatabaseMetaData); + + // create the composed name like DOMAIN.USER.TABLE1 + aComposedName = ::dbtools::composeTableName(m_pImpl->m_xDatabaseMetaData, + aCatalog.hasValue() ? ::comphelper::getString(aCatalog) : OUString(), + aSchema, + aTableName, + false, + ::dbtools::EComposeRule::InDataManipulation); + + // if there is no alias for the table name assign the original name to it + if ( aTableRange.isEmpty() ) + aTableRange = aComposedName; + + // get the object representing this table/query + OSQLTable aTable = impl_locateRecordSource( aComposedName ); + if ( aTable.is() ) + _rTables[ aTableRange ] = aTable; +} + +void OSQLParseTreeIterator::impl_fillJoinConditions(const OSQLParseNode* i_pJoinCondition) +{ + if (i_pJoinCondition->count() == 3 && // Expression with brackets + SQL_ISPUNCTUATION(i_pJoinCondition->getChild(0),"(") && + SQL_ISPUNCTUATION(i_pJoinCondition->getChild(2),")")) + { + impl_fillJoinConditions(i_pJoinCondition->getChild(1)); + } + else if (SQL_ISRULEOR2(i_pJoinCondition,search_condition,boolean_term) && // AND/OR logic operation: + i_pJoinCondition->count() == 3) + { + // Only allow AND logic operation + if ( SQL_ISTOKEN(i_pJoinCondition->getChild(1),AND) ) + { + impl_fillJoinConditions(i_pJoinCondition->getChild(0)); + impl_fillJoinConditions(i_pJoinCondition->getChild(1)); + } + } + else if (SQL_ISRULE(i_pJoinCondition,comparison_predicate)) + { + // only the comparison of columns is allowed + OSL_ENSURE(i_pJoinCondition->count() == 3,"OQueryDesignView::InsertJoinConnection: error in the parse tree"); + if (SQL_ISRULE(i_pJoinCondition->getChild(0),column_ref) && + SQL_ISRULE(i_pJoinCondition->getChild(2),column_ref) && + i_pJoinCondition->getChild(1)->getNodeType() == SQLNodeType::Equal) + { + m_pImpl->m_aJoinConditions.push_back( TNodePair(i_pJoinCondition->getChild(0),i_pJoinCondition->getChild(2)) ); + } + } +} + +std::vector< TNodePair >& OSQLParseTreeIterator::getJoinConditions() const +{ + return m_pImpl->m_aJoinConditions; +} + +void OSQLParseTreeIterator::getQualified_join( OSQLTables& _rTables, const OSQLParseNode *pTableRef, OUString& aTableRange ) +{ + OSL_PRECOND( SQL_ISRULE( pTableRef, cross_union ) || SQL_ISRULE( pTableRef, qualified_join ) , + "OSQLParseTreeIterator::getQualified_join: illegal node!" ); + + aTableRange.clear(); + + const OSQLParseNode* pNode = getTableNode(_rTables,pTableRef->getChild(0),aTableRange); + if ( isTableNode( pNode ) ) + traverseOneTableName( _rTables, pNode, aTableRange ); + + sal_uInt32 nPos = 4; + if( SQL_ISRULE(pTableRef,cross_union) || pTableRef->getChild(1)->getTokenID() != SQL_TOKEN_NATURAL) + { + nPos = 3; + // join_condition,named_columns_join + if ( SQL_ISRULE( pTableRef, qualified_join ) ) + { + const OSQLParseNode* pJoin_spec = pTableRef->getChild(4); + if ( SQL_ISRULE( pJoin_spec, join_condition ) ) + { + impl_fillJoinConditions(pJoin_spec->getChild(1)); + } + else + { + const OSQLParseNode* pColumnCommalist = pJoin_spec->getChild(2); + // All columns in the column_commalist ... + for (size_t i = 0; i < pColumnCommalist->count(); i++) + { + const OSQLParseNode * pCol = pColumnCommalist->getChild(i); + // add twice because the column must exists in both tables + m_pImpl->m_aJoinConditions.push_back( TNodePair(pCol,pCol) ); + } + } + } + } + + pNode = getTableNode(_rTables,pTableRef->getChild(nPos),aTableRange); + if ( isTableNode( pNode ) ) + traverseOneTableName( _rTables, pNode, aTableRange ); +} + +const OSQLParseNode* OSQLParseTreeIterator::getTableNode( OSQLTables& _rTables, const OSQLParseNode *pTableRef,OUString& rTableRange ) +{ + OSL_PRECOND( SQL_ISRULE( pTableRef, table_ref ) || SQL_ISRULE( pTableRef, joined_table ) + || SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ), + "OSQLParseTreeIterator::getTableNode: only to be called for table_ref nodes!" ); + + const OSQLParseNode* pTableNameNode = nullptr; + + if ( SQL_ISRULE( pTableRef, joined_table ) ) + { + getQualified_join( _rTables, pTableRef->getChild(1), rTableRange ); + } + if ( SQL_ISRULE( pTableRef, qualified_join ) || SQL_ISRULE( pTableRef, cross_union ) ) + { + getQualified_join( _rTables, pTableRef, rTableRange ); + } + else + { + rTableRange = OSQLParseNode::getTableRange(pTableRef); + if ( ( pTableRef->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}' + || ( pTableRef->count() == 5 ) // '(' joined_table ')' range_variable op_column_commalist + ) + { + getQualified_join( _rTables, pTableRef->getChild(6 - pTableRef->count()), rTableRange ); + } + else if ( pTableRef->count() == 3 ) // subquery range_variable op_column_commalist || '(' joined_table ')' + { + const OSQLParseNode* pSubQuery = pTableRef->getChild(0); + if ( pSubQuery->isToken() ) + { + getQualified_join( _rTables, pTableRef->getChild(1), rTableRange ); + } + else + { + OSL_ENSURE( pSubQuery->count() == 3, "sub queries should have 3 children!" ); + const OSQLParseNode* pQueryExpression = pSubQuery->getChild(1); + if ( SQL_ISRULE( pQueryExpression, select_statement ) ) + { + getSelect_statement( *m_pImpl->m_pSubTables, pQueryExpression ); + // TODO: now, we need to setup an OSQLTable from pQueryExpression in some way + // and stick it in _rTables[rTableRange]. Probably fake it by + // setting up a full OSQLParseTreeIterator on pQueryExpression + // and using its m_aSelectColumns + // This is necessary in stuff like "SELECT * FROM tbl1 INNER JOIN (SELECT foo, bar FROM tbl2) AS tbl3" + // so that setSelectColumnName() can expand the "*" correctly. + // See e.g. R_UserAndLastSubscription query of https://bugs.libreoffice.org/attachment.cgi?id=71871 + } + else + { + SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: subquery which is no select_statement: not yet implemented!" ); + } + } + } + else if ( pTableRef->count() == 2 ) // table_node table_primary_as_range_column + { + pTableNameNode = pTableRef->getChild(0); + } + else + SAL_WARN( "connectivity.parse", "OSQLParseTreeIterator::getTableNode: unhandled case!" ); + } + + return pTableNameNode; +} + +void OSQLParseTreeIterator::getSelect_statement(OSQLTables& _rTables,const OSQLParseNode* pSelect) +{ + if(SQL_ISRULE(pSelect,union_statement)) + { + getSelect_statement(_rTables,pSelect->getChild(0)); + //getSelect_statement(pSelect->getChild(3)); + return; + } + OSQLParseNode * pTableRefCommalist = pSelect->getChild(3)->getChild(0)->getChild(1); + + OSL_ENSURE(pTableRefCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(SQL_ISRULE(pTableRefCommalist,table_ref_commalist),"OSQLParseTreeIterator: error in parse tree!"); + + const OSQLParseNode* pTableName = nullptr; + OUString aTableRange; + for (size_t i = 0; i < pTableRefCommalist->count(); i++) + { // Process FROM clause + aTableRange.clear(); + + const OSQLParseNode* pTableListElement = pTableRefCommalist->getChild(i); + if ( isTableNode( pTableListElement ) ) + { + traverseOneTableName( _rTables, pTableListElement, aTableRange ); + } + else if ( SQL_ISRULE( pTableListElement, table_ref ) ) + { + // Table references can be made up of table names, table names (+),'('joined_table')'(+) + pTableName = pTableListElement->getChild(0); + if( isTableNode( pTableName ) ) + { // Found table names + aTableRange = OSQLParseNode::getTableRange(pTableListElement); + traverseOneTableName( _rTables, pTableName, aTableRange ); + } + else if(SQL_ISPUNCTUATION(pTableName,"{")) + { // '{' SQL_TOKEN_OJ joined_table '}' + getQualified_join( _rTables, pTableListElement->getChild(2), aTableRange ); + } + else + { // '(' joined_table ')' range_variable op_column_commalist + getTableNode( _rTables, pTableListElement, aTableRange ); + } + } + else if (SQL_ISRULE( pTableListElement, qualified_join ) || SQL_ISRULE( pTableListElement, cross_union ) ) + { + getQualified_join( _rTables, pTableListElement, aTableRange ); + } + else if ( SQL_ISRULE( pTableListElement, joined_table ) ) + { + getQualified_join( _rTables, pTableListElement->getChild(1), aTableRange ); + } + + // if (! aIteratorStatus.IsSuccessful()) break; + } +} + +bool OSQLParseTreeIterator::traverseTableNames(OSQLTables& _rTables) +{ + if ( m_pParseTree == nullptr ) + return false; + + OSQLParseNode* pTableName = nullptr; + + switch ( m_eStatementType ) + { + case OSQLStatementType::Select: + getSelect_statement( _rTables, m_pParseTree ); + break; + + case OSQLStatementType::CreateTable: + case OSQLStatementType::Insert: + case OSQLStatementType::Delete: + pTableName = m_pParseTree->getChild(2); + break; + + case OSQLStatementType::Update: + pTableName = m_pParseTree->getChild(1); + break; + default: + break; + } + + if ( pTableName ) + { + traverseOneTableName( _rTables, pTableName, OUString() ); + } + + return !hasErrors(); +} + +OUString OSQLParseTreeIterator::getColumnAlias(const OSQLParseNode* _pDerivedColumn) +{ + OSL_ENSURE(SQL_ISRULE(_pDerivedColumn,derived_column),"No derived column!"); + OUString sColumnAlias; + if(_pDerivedColumn->getChild(1)->count() == 2) + sColumnAlias = _pDerivedColumn->getChild(1)->getChild(1)->getTokenValue(); + else if(!_pDerivedColumn->getChild(1)->isRule()) + sColumnAlias = _pDerivedColumn->getChild(1)->getTokenValue(); + return sColumnAlias; +} + + +namespace +{ + void lcl_getColumnRange( const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection, + OUString& _out_rColumnName, OUString& _out_rTableRange, + const OSQLColumns* _pSelectColumns, OUString& _out_rColumnAliasIfPresent ) + { + _out_rColumnName.clear(); + _out_rTableRange.clear(); + _out_rColumnAliasIfPresent.clear(); + if ( SQL_ISRULE( _pColumnRef, column_ref ) ) + { + if( _pColumnRef->count() > 1 ) + { + for ( sal_Int32 i=0; i<static_cast<sal_Int32>(_pColumnRef->count())-2; ++i ) + _pColumnRef->getChild(i)->parseNodeToStr( _out_rTableRange, _rxConnection, nullptr, false, false ); + _out_rColumnName = _pColumnRef->getChild( _pColumnRef->count()-1 )->getChild(0)->getTokenValue(); + } + else + _out_rColumnName = _pColumnRef->getChild(0)->getTokenValue(); + + // look up the column in the select column, to find a possible alias + if ( _pSelectColumns ) + { + for (const Reference< XPropertySet >& xColumn : *_pSelectColumns) + { + try + { + OUString sName, sTableName; + xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) >>= sName; + xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TABLENAME ) ) >>= sTableName; + if ( sName == _out_rColumnName && ( _out_rTableRange.isEmpty() || sTableName == _out_rTableRange ) ) + { + xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= _out_rColumnAliasIfPresent; + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.parse"); + } + } + } + } + else if(SQL_ISRULE(_pColumnRef,general_set_fct) || SQL_ISRULE(_pColumnRef,set_fct_spec)) + { // Function + _pColumnRef->parseNodeToStr( _out_rColumnName, _rxConnection ); + } + else if(_pColumnRef->getNodeType() == SQLNodeType::Name) + _out_rColumnName = _pColumnRef->getTokenValue(); + } +} + + +void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef, + OUString& _rColumnName, + OUString& _rTableRange) const +{ + OUString sDummy; + lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, nullptr, sDummy ); +} + + +void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef, + OUString& _rColumnName, + OUString& _rTableRange, + OUString& _out_rColumnAliasIfPresent ) const +{ + lcl_getColumnRange( _pColumnRef, m_pImpl->m_xConnection, _rColumnName, _rTableRange, &*m_aSelectColumns, _out_rColumnAliasIfPresent ); +} + + +void OSQLParseTreeIterator::getColumnRange( const OSQLParseNode* _pColumnRef, + const Reference< XConnection >& _rxConnection, OUString& _out_rColumnName, OUString& _out_rTableRange ) +{ + OUString sDummy; + lcl_getColumnRange( _pColumnRef, _rxConnection, _out_rColumnName, _out_rTableRange, nullptr, sDummy ); +} + + +void OSQLParseTreeIterator::traverseCreateColumns(const OSQLParseNode* pSelectNode) +{ + // aIteratorStatus.Clear(); + + if (!pSelectNode || m_eStatementType != OSQLStatementType::CreateTable || m_pImpl->m_pTables->empty()) + { + impl_appendError( IParseContext::ErrorCode::General ); + return; + } + if (!SQL_ISRULE(pSelectNode,base_table_element_commalist)) + return ; + + for (size_t i = 0; i < pSelectNode->count(); i++) + { + OSQLParseNode *pColumnRef = pSelectNode->getChild(i); + + if (SQL_ISRULE(pColumnRef,column_def)) + { + OUString aColumnName; + OUString aTypeName; + sal_Int32 nType = DataType::VARCHAR; + aColumnName = pColumnRef->getChild(0)->getTokenValue(); + + OSQLParseNode *pDatatype = pColumnRef->getChild(1); + if (pDatatype && SQL_ISRULE(pDatatype,character_string_type)) + { + const OSQLParseNode *pType = pDatatype->getChild(0); + aTypeName = pType->getTokenValue(); + if (pDatatype->count() == 2 && (pType->getTokenID() == SQL_TOKEN_CHAR || pType->getTokenID() == SQL_TOKEN_CHARACTER )) + nType = DataType::CHAR; + } + else if(pDatatype && pDatatype->getNodeType() == SQLNodeType::Keyword) + { + aTypeName = "VARCHAR"; + } + + if (!aTypeName.isEmpty()) + { + //TODO:Create a new class for create statement to handle field length + OParseColumn* pColumn = new OParseColumn(aColumnName,aTypeName,OUString(),OUString(), + ColumnValue::NULLABLE_UNKNOWN,0,0,nType,false,false,isCaseSensitive(), + OUString(),OUString(),OUString()); + pColumn->setFunction(false); + pColumn->setRealName(aColumnName); + + Reference< XPropertySet> xCol = pColumn; + m_aCreateColumns->push_back(xCol); + } + } + + } +} + +bool OSQLParseTreeIterator::traverseSelectColumnNames(const OSQLParseNode* pSelectNode) +{ + if ( !( m_pImpl->m_nIncludeMask & TraversalParts::SelectColumns ) ) + return true; + + if (!pSelectNode || m_eStatementType != OSQLStatementType::Select || m_pImpl->m_pTables->empty()) + { + impl_appendError( IParseContext::ErrorCode::General ); + return false; + } + + if(SQL_ISRULE(pSelectNode,union_statement)) + { + return traverseSelectColumnNames( pSelectNode->getChild( 0 ) ) + /*&& traverseSelectColumnNames( pSelectNode->getChild( 3 ) )*/; + } + + // nyi: more checks for correct structure! + if (pSelectNode->getChild(2)->isRule() && SQL_ISPUNCTUATION(pSelectNode->getChild(2)->getChild(0),"*")) + { + // SELECT * ... + setSelectColumnName(m_aSelectColumns, "*", "", ""); + } + else if (SQL_ISRULE(pSelectNode->getChild(2),scalar_exp_commalist)) + { + // SELECT column[,column] or SELECT COUNT(*) ... + OSQLParseNode * pSelection = pSelectNode->getChild(2); + + for (size_t i = 0; i < pSelection->count(); i++) + { + OSQLParseNode *pColumnRef = pSelection->getChild(i); + + //if (SQL_ISRULE(pColumnRef,select_sublist)) + if (SQL_ISRULE(pColumnRef,derived_column) && + SQL_ISRULE(pColumnRef->getChild(0),column_ref) && + pColumnRef->getChild(0)->count() == 3 && + SQL_ISPUNCTUATION(pColumnRef->getChild(0)->getChild(2),"*")) + { + // All the table's columns + OUString aTableRange; + pColumnRef->getChild(0)->parseNodeToStr( aTableRange, m_pImpl->m_xConnection, nullptr, false, false ); + setSelectColumnName(m_aSelectColumns, "*", "", aTableRange); + continue; + } + else if (SQL_ISRULE(pColumnRef,derived_column)) + { + OUString aColumnAlias(getColumnAlias(pColumnRef)); // can be empty + OUString sColumnName; + OUString aTableRange; + sal_Int32 nType = DataType::VARCHAR; + bool bFkt(false); + pColumnRef = pColumnRef->getChild(0); + while ( + pColumnRef->getKnownRuleID() != OSQLParseNode::subquery && + pColumnRef->count() == 3 && + SQL_ISPUNCTUATION(pColumnRef->getChild(0),"(") && + SQL_ISPUNCTUATION(pColumnRef->getChild(2),")") + ) + pColumnRef = pColumnRef->getChild(1); + + if (SQL_ISRULE(pColumnRef,column_ref)) + { + getColumnRange(pColumnRef,sColumnName,aTableRange); + OSL_ENSURE(!sColumnName.isEmpty(),"Column name must not be empty!"); + } + else /*if (SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec) || + SQL_ISRULE(pColumnRef,position_exp) || SQL_ISRULE(pColumnRef,extract_exp) || + SQL_ISRULE(pColumnRef,length_exp) || SQL_ISRULE(pColumnRef,char_value_fct)|| + SQL_ISRULE(pColumnRef,num_value_exp) || SQL_ISRULE(pColumnRef,term))*/ + { + // Function call present + pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection ); + // check if the column is also a parameter + traverseSearchCondition(pColumnRef); // num_value_exp + + if ( pColumnRef->isRule() ) + { + // FIXME: the if condition is not quite right + // many expressions are rules, e.g. "5+3" + // or even: "colName + 1" + bFkt = true; + nType = getFunctionReturnType(pColumnRef); + } + } + /* + else + { + aIteratorStatus.setStatementTooComplex(); + return; + } + */ + if(aColumnAlias.isEmpty()) + aColumnAlias = sColumnName; + setSelectColumnName(m_aSelectColumns,sColumnName,aColumnAlias,aTableRange,bFkt,nType,SQL_ISRULE(pColumnRef,general_set_fct) || SQL_ISRULE(pColumnRef,set_fct_spec)); + } + } + } + + return !hasErrors(); +} + + +bool OSQLParseTreeIterator::traverseOrderByColumnNames(const OSQLParseNode* pSelectNode) +{ + traverseByColumnNames( pSelectNode, true ); + return !hasErrors(); +} + +void OSQLParseTreeIterator::traverseByColumnNames(const OSQLParseNode* pSelectNode, bool _bOrder) +{ + // aIteratorStatus.Clear(); + + if (pSelectNode == nullptr) + { + //aIteratorStatus.setInvalidStatement(); + return; + } + + if (m_eStatementType != OSQLStatementType::Select) + { + //aIteratorStatus.setInvalidStatement(); + return; + } + + if(SQL_ISRULE(pSelectNode,union_statement)) + { + traverseByColumnNames(pSelectNode->getChild(0),_bOrder); + return; + } + + OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!"); + + OSQLParseNode * pTableExp = pSelectNode->getChild(3); + OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator:table_exp error in parse tree!"); + OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); + + sal_uInt32 nPos = ( _bOrder ? ORDER_BY_CHILD_POS : 2 ); + + OSQLParseNode * pOptByClause = pTableExp->getChild(nPos); + OSL_ENSURE(pOptByClause != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + if ( pOptByClause->count() == 0 ) + return; + + OSL_ENSURE(pOptByClause->count() == 3,"OSQLParseTreeIterator: error in parse tree!"); + + OSQLParseNode * pOrderingSpecCommalist = pOptByClause->getChild(2); + OSL_ENSURE(pOrderingSpecCommalist != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(!_bOrder || SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OSQLParseTreeIterator:ordering_spec_commalist error in parse tree!"); + OSL_ENSURE(pOrderingSpecCommalist->count() > 0,"OSQLParseTreeIterator: error in parse tree!"); + + OUString sColumnName; + OUString aTableRange; + sal_uInt32 nCount = pOrderingSpecCommalist->count(); + for (sal_uInt32 i = 0; i < nCount; ++i) + { + OSQLParseNode* pColumnRef = pOrderingSpecCommalist->getChild(i); + OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + if ( _bOrder ) + { + OSL_ENSURE(SQL_ISRULE(pColumnRef,ordering_spec),"OSQLParseTreeIterator:ordering_spec error in parse tree!"); + OSL_ENSURE(pColumnRef->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); + + pColumnRef = pColumnRef->getChild(0); + } + OSL_ENSURE(pColumnRef != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + aTableRange.clear(); + sColumnName.clear(); + if ( SQL_ISRULE(pColumnRef,column_ref) ) + { + // Column name (and TableRange): + getColumnRange(pColumnRef,sColumnName,aTableRange); + } + else + { // here I found a predicate + pColumnRef->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false ); + } + OSL_ENSURE(!sColumnName.isEmpty(),"sColumnName must not be empty!"); + if ( _bOrder ) + { + // Ascending/Descending + OSQLParseNode * pOptAscDesc = pColumnRef->getParent()->getChild(1); + OSL_ENSURE(pOptAscDesc != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + + bool bAscending = ! (pOptAscDesc && SQL_ISTOKEN(pOptAscDesc,DESC)); + setOrderByColumnName(sColumnName, aTableRange,bAscending); + } + else + setGroupByColumnName(sColumnName, aTableRange); + } +} + +bool OSQLParseTreeIterator::traverseGroupByColumnNames(const OSQLParseNode* pSelectNode) +{ + traverseByColumnNames( pSelectNode, false ); + return !hasErrors(); +} + + +namespace +{ + OUString lcl_generateParameterName( const OSQLParseNode& _rParentNode, const OSQLParseNode& _rParamNode ) + { + OUString sColumnName( "param" ); + const sal_Int32 nCount = static_cast<sal_Int32>(_rParentNode.count()); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + if ( _rParentNode.getChild(i) == &_rParamNode ) + { + sColumnName += OUString::number( i+1 ); + break; + } + } + return sColumnName; + } +} + + +void OSQLParseTreeIterator::traverseParameters(const OSQLParseNode* _pNode) +{ + if ( _pNode == nullptr ) + return; + + OUString sColumnName, sTableRange, aColumnAlias; + const OSQLParseNode* pParent = _pNode->getParent(); + if ( pParent != nullptr ) + { + if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X + { + sal_uInt32 nPos = 0; + if ( pParent->getChild(nPos) == _pNode ) + nPos = 2; + const OSQLParseNode* pOther = pParent->getChild(nPos); + if ( SQL_ISRULE( pOther, column_ref ) ) + getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias); + else + pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false ); + } // if ( SQL_ISRULE(pParent,comparison_predicate) ) // x = X + else if ( SQL_ISRULE(pParent,other_like_predicate_part_2) ) + { + const OSQLParseNode* pOther = pParent->getParent()->getChild(0); + if ( SQL_ISRULE( pOther, column_ref ) ) + getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias); + else + pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false ); + } + else if ( SQL_ISRULE(pParent,between_predicate_part_2) ) + { + const OSQLParseNode* pOther = pParent->getParent()->getChild(0); + if ( SQL_ISRULE( pOther, column_ref ) ) + getColumnRange( pOther, sColumnName, sTableRange, aColumnAlias); + else + { + pOther->parseNodeToStr( sColumnName, m_pImpl->m_xConnection, nullptr, false, false ); + lcl_generateParameterName( *pParent, *_pNode ); + } + } + else if ( pParent->getNodeType() == SQLNodeType::CommaListRule ) + { + lcl_generateParameterName( *pParent, *_pNode ); + } + } + traverseParameter( _pNode, pParent, sColumnName, sTableRange, aColumnAlias ); + const sal_uInt32 nCount = _pNode->count(); + for (sal_uInt32 i = 0; i < nCount; ++i) + { + const OSQLParseNode* pChild = _pNode->getChild(i); + traverseParameters( pChild ); + } +} + +bool OSQLParseTreeIterator::traverseSelectionCriteria(const OSQLParseNode* pSelectNode) +{ + if ( pSelectNode == nullptr ) + return false; + + + // Analyse parse tree (depending on statement type) + // and set pointer to WHERE clause: + OSQLParseNode * pWhereClause = nullptr; + + if (m_eStatementType == OSQLStatementType::Select) + { + if(SQL_ISRULE(pSelectNode,union_statement)) + { + return traverseSelectionCriteria( pSelectNode->getChild( 0 ) ) + && traverseSelectionCriteria( pSelectNode->getChild( 3 ) ); + } + OSL_ENSURE(pSelectNode->count() >= 4,"OSQLParseTreeIterator: error in parse tree!"); + + OSQLParseNode * pTableExp = pSelectNode->getChild(3); + OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); + + pWhereClause = pTableExp->getChild(1); + } else if (SQL_ISRULE(pSelectNode,update_statement_searched)) { + OSL_ENSURE(pSelectNode->count() == 5,"OSQLParseTreeIterator: error in parse tree!"); + pWhereClause = pSelectNode->getChild(4); + } else if (SQL_ISRULE(pSelectNode,delete_statement_searched)) { + OSL_ENSURE(pSelectNode->count() == 4,"OSQLParseTreeIterator: error in parse tree!"); + pWhereClause = pSelectNode->getChild(3); + } else if (SQL_ISRULE(pSelectNode,delete_statement_positioned)) { + // nyi + SAL_WARN( "connectivity.parse","OSQLParseTreeIterator::getSelectionCriteria: positioned nyi"); + } else { + // Other statement, no selection criteria + return false; + } + + if (!pWhereClause || !SQL_ISRULE(pWhereClause,where_clause)) + { + // The WHERE clause is optional most of the time; which means it could be a "optional_where_clause". + OSL_ENSURE(pWhereClause && SQL_ISRULE(pWhereClause,opt_where_clause),"OSQLParseTreeIterator: error in parse tree!"); + return false; + } + + // But if it's a where_clause, then it must not be empty + OSL_ENSURE(pWhereClause->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); + + OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1); + OSL_ENSURE(pComparisonPredicate != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + + + // Process the comparison criteria now + + + traverseSearchCondition(pComparisonPredicate); + + return !hasErrors(); +} + + +void OSQLParseTreeIterator::traverseSearchCondition(OSQLParseNode const * pSearchCondition) +{ + if ( + SQL_ISRULE(pSearchCondition,boolean_primary) && + pSearchCondition->count() == 3 && + SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") && + SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")") + ) + { + // Round brackets + traverseSearchCondition(pSearchCondition->getChild(1)); + } + // The first element is an OR logical operation + else if ( SQL_ISRULE(pSearchCondition,search_condition) && pSearchCondition->count() == 3 ) + { + // if this assert fails, the SQL grammar has changed! + assert(SQL_ISTOKEN(pSearchCondition->getChild(1),OR)); + // Then process recursively (use the same row) ... + traverseSearchCondition(pSearchCondition->getChild(0)); +// if (! aIteratorStatus.IsSuccessful()) +// return; + + // Continue with the right child + traverseSearchCondition(pSearchCondition->getChild(2)); + } + // The first element is an AND logical operation (again) + else if ( SQL_ISRULE(pSearchCondition,boolean_term) && pSearchCondition->count() == 3 ) + { + // Then process recursively (use the same row) + traverseSearchCondition(pSearchCondition->getChild(0)); +// if (! aIteratorStatus.IsSuccessful()) +// return; + + // Continue with the right child + traverseSearchCondition(pSearchCondition->getChild(2)); + } + // Else, process single search criteria (like =, !=, ..., LIKE, IS NULL etc.) + else if (SQL_ISRULE(pSearchCondition,comparison_predicate) ) + { + OUString aValue; + pSearchCondition->getChild(2)->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false ); + traverseOnePredicate(pSearchCondition->getChild(0),aValue,pSearchCondition->getChild(2)); + impl_fillJoinConditions(pSearchCondition); +// if (! aIteratorStatus.IsSuccessful()) +// return; + } + else if (SQL_ISRULE(pSearchCondition,like_predicate) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/) + { + OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); + const OSQLParseNode* pPart2 = pSearchCondition->getChild(1); + + sal_Int32 nCurentPos = pPart2->count()-2; + + OSQLParseNode * pNum_value_exp = pPart2->getChild(nCurentPos); + OSQLParseNode * pOptEscape = pPart2->getChild(nCurentPos+1); + + OSL_ENSURE(pNum_value_exp != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(pOptEscape != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + + if (pOptEscape->count() != 0) + { + // aIteratorStatus.setStatementTooComplex(); + return; + } + + OUString aValue; + OSQLParseNode * pParam = nullptr; + if (SQL_ISRULE(pNum_value_exp,parameter)) + pParam = pNum_value_exp; + else if(pNum_value_exp->isToken()) + // Normal value + aValue = pNum_value_exp->getTokenValue(); + else + { + pNum_value_exp->parseNodeToStr( aValue, m_pImpl->m_xConnection, nullptr, false, false ); + pParam = pNum_value_exp; + } + + traverseOnePredicate(pSearchCondition->getChild(0),aValue,pParam); +// if (! aIteratorStatus.IsSuccessful()) +// return; + } + else if (SQL_ISRULE(pSearchCondition,in_predicate)) + { + OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); + const OSQLParseNode* pPart2 = pSearchCondition->getChild(1); + + traverseSearchCondition(pSearchCondition->getChild(0)); + // if (! aIteratorStatus.IsSuccessful()) return; + + OSQLParseNode* pChild = pPart2->getChild(2); + if ( SQL_ISRULE(pChild->getChild(0),subquery) ) + { + traverseTableNames( *m_pImpl->m_pSubTables ); + traverseSelectionCriteria(pChild->getChild(0)->getChild(1)); + } + else + { // '(' value_exp_commalist ')' + pChild = pChild->getChild(1); + sal_Int32 nCount = pChild->count(); + for (sal_Int32 i=0; i < nCount; ++i) + { + traverseSearchCondition(pChild->getChild(i)); + } + } + } + else if (SQL_ISRULE(pSearchCondition,test_for_null) /*&& SQL_ISRULE(pSearchCondition->getChild(0),column_ref)*/) + { + OSL_ENSURE(pSearchCondition->count() == 2,"OSQLParseTreeIterator: error in parse tree!"); + const OSQLParseNode* pPart2 = pSearchCondition->getChild(1); + OSL_ENSURE(SQL_ISTOKEN(pPart2->getChild(0),IS),"OSQLParseTreeIterator: error in parse tree!"); + + OUString aString; + traverseOnePredicate(pSearchCondition->getChild(0),aString,nullptr); + // if (! aIteratorStatus.IsSuccessful()) return; + } + else if (SQL_ISRULE(pSearchCondition,num_value_exp) || SQL_ISRULE(pSearchCondition,term)) + { + OUString aString; + traverseOnePredicate(pSearchCondition->getChild(0),aString,pSearchCondition->getChild(0)); + traverseOnePredicate(pSearchCondition->getChild(2),aString,pSearchCondition->getChild(2)); + } + // Just pass on the error +} + +void OSQLParseTreeIterator::traverseParameter(const OSQLParseNode* _pParseNode + ,const OSQLParseNode* _pParentNode + ,const OUString& _aColumnName + ,OUString& _aTableRange + ,const OUString& _rColumnAlias) +{ + if ( !SQL_ISRULE( _pParseNode, parameter ) ) + return; + + if ( !( m_pImpl->m_nIncludeMask & TraversalParts::Parameters ) ) + // parameters not to be included in the traversal + return; + + OSL_ENSURE(_pParseNode->count() > 0,"OSQLParseTreeIterator: error in parse tree!"); + OSQLParseNode * pMark = _pParseNode->getChild(0); + OUString sParameterName; + + if (SQL_ISPUNCTUATION(pMark,"?")) + { + sParameterName = !_rColumnAlias.isEmpty() + ? _rColumnAlias + : !_aColumnName.isEmpty() + ? _aColumnName + : OUString("?"); + } + else if (SQL_ISPUNCTUATION(pMark,":")) + { + sParameterName = _pParseNode->getChild(1)->getTokenValue(); + } + else if (SQL_ISPUNCTUATION(pMark,"[")) + { + sParameterName = _pParseNode->getChild(1)->getTokenValue(); + } + else + { + SAL_WARN( "connectivity.parse","OSQLParseTreeIterator: error in parse tree!"); + } + + // found a parameter + if ( _pParentNode && (SQL_ISRULE(_pParentNode,general_set_fct) || SQL_ISRULE(_pParentNode,set_fct_spec)) ) + {// found a function as column_ref + OUString sFunctionName; + _pParentNode->getChild(0)->parseNodeToStr( sFunctionName, m_pImpl->m_xConnection, nullptr, false, false ); + const sal_uInt32 nCount = _pParentNode->count(); + sal_uInt32 i = 0; + for(; i < nCount;++i) + { + if ( _pParentNode->getChild(i) == _pParseNode ) + break; + } + sal_Int32 nType = ::connectivity::OSQLParser::getFunctionParameterType( _pParentNode->getChild(0)->getTokenID(), i-1); + + OParseColumn* pColumn = new OParseColumn( sParameterName, + OUString(), + OUString(), + OUString(), + ColumnValue::NULLABLE_UNKNOWN, + 0, + 0, + nType, + false, + false, + isCaseSensitive(), + OUString(), + OUString(), + OUString()); + pColumn->setFunction(true); + pColumn->setAggregateFunction(true); + pColumn->setRealName(sFunctionName); + m_aParameters->push_back(pColumn); + } + else + { + bool bNotFound = true; + OSQLColumns::const_iterator aIter = ::connectivity::find( + m_aSelectColumns->begin(), + m_aSelectColumns->end(), + _aColumnName,::comphelper::UStringMixEqual( isCaseSensitive() ) + ); + if(aIter != m_aSelectColumns->end()) + { + OParseColumn* pNewColumn = new OParseColumn(*aIter,isCaseSensitive()); + pNewColumn->setName(sParameterName); + pNewColumn->setRealName(_aColumnName); + m_aParameters->push_back(pNewColumn); + bNotFound = false; + } + else if(!_aColumnName.isEmpty())// search in the tables for the right one + { + + Reference<XPropertySet> xColumn = findColumn( _aColumnName, _aTableRange, true ); + + if ( xColumn.is() ) + { + OParseColumn* pNewColumn = new OParseColumn(xColumn,isCaseSensitive()); + pNewColumn->setName(sParameterName); + pNewColumn->setRealName(_aColumnName); + m_aParameters->push_back(pNewColumn); + bNotFound = false; + } + } + if ( bNotFound ) + { + sal_Int32 nType = DataType::VARCHAR; + OSQLParseNode* pParent = _pParentNode ? _pParentNode->getParent() : nullptr; + if ( pParent && (SQL_ISRULE(pParent,general_set_fct) || SQL_ISRULE(pParent,set_fct_spec)) ) + { + const sal_uInt32 nCount = _pParentNode->count(); + sal_uInt32 i = 0; + for(; i < nCount;++i) + { + if ( _pParentNode->getChild(i) == _pParseNode ) + break; + } + nType = ::connectivity::OSQLParser::getFunctionParameterType( pParent->getChild(0)->getTokenID(), i+1); + } + + OUString aNewColName( getUniqueColumnName( sParameterName ) ); + + OParseColumn* pColumn = new OParseColumn(aNewColName, + OUString(), + OUString(), + OUString(), + ColumnValue::NULLABLE_UNKNOWN, + 0, + 0, + nType, + false, + false, + isCaseSensitive(), + OUString(), + OUString(), + OUString()); + pColumn->setName(aNewColName); + pColumn->setRealName(sParameterName); + m_aParameters->push_back(pColumn); + } + } +} + +void OSQLParseTreeIterator::traverseOnePredicate( + OSQLParseNode const * pColumnRef, + OUString& rValue, + OSQLParseNode const * pParseNode) +{ + if ( !pParseNode ) + return; + + // Column name (and TableRange): + OUString aColumnName, aTableRange, sColumnAlias; + getColumnRange( pColumnRef, aColumnName, aTableRange, sColumnAlias); + + OUString aName; + + /*if (SQL_ISRULE(pParseNode,parameter)) + traverseParameter( pParseNode, pColumnRef, aColumnName, aTableRange, sColumnAlias ); + else */if (SQL_ISRULE(pParseNode,column_ref))// Column-Name (and TableRange): + getColumnRange(pParseNode,aName,rValue); + else + { + traverseSearchCondition(pParseNode); + // if (! aIteratorStatus.IsSuccessful()) return; + } +} + + +void OSQLParseTreeIterator::traverseAll() +{ + impl_traverse( TraversalParts::All ); +} + + +void OSQLParseTreeIterator::impl_traverse( TraversalParts _nIncludeMask ) +{ + // resets our errors + m_xErrors.reset(); + + m_pImpl->m_nIncludeMask = _nIncludeMask; + + if ( !traverseTableNames( *m_pImpl->m_pTables ) ) + return; + + switch ( m_eStatementType ) + { + case OSQLStatementType::Select: + { + const OSQLParseNode* pSelectNode = m_pParseTree; + traverseParameters( pSelectNode ); + if ( !traverseSelectColumnNames( pSelectNode ) + || !traverseOrderByColumnNames( pSelectNode ) + || !traverseGroupByColumnNames( pSelectNode ) + || !traverseSelectionCriteria( pSelectNode ) + ) + return; + } + break; + case OSQLStatementType::CreateTable: + { + //0 | 1 | 2 |3| 4 |5 + //create table sc.foo ( a char(20), b char ) + const OSQLParseNode* pCreateNode = m_pParseTree->getChild(4); + traverseCreateColumns(pCreateNode); + } + break; + case OSQLStatementType::Insert: + break; + default: + break; + } +} + +// Dummy implementations + + +OSQLTable OSQLParseTreeIterator::impl_createTableObject( const OUString& rTableName, + const OUString& rCatalogName, const OUString& rSchemaName ) +{ + OSL_PRECOND( m_eStatementType == OSQLStatementType::CreateTable, + "OSQLParseTreeIterator::impl_createTableObject: only to be called for CREATE TABLE statements!" ); + // (in all other cases, m_pTables is to contain the table objects as obtained from the tables + // container of the connection (m_xTablesContainer) + + OSQLTable aReturnTable = new OTable( + nullptr, + false, + rTableName, + "Table", + "New Created Table", + rSchemaName, + rCatalogName + ); + return aReturnTable; +} + +void OSQLParseTreeIterator::appendColumns(::rtl::Reference<OSQLColumns> const & _rColumns,const OUString& _rTableAlias,const OSQLTable& _rTable) +{ + if (!_rTable.is()) + return; + + Reference<XNameAccess> xColumns = _rTable->getColumns(); + if ( !xColumns.is() ) + return; + + Sequence< OUString > aColNames = xColumns->getElementNames(); + const OUString* pBegin = aColNames.getConstArray(); + const OUString* pEnd = pBegin + aColNames.getLength(); + + for(;pBegin != pEnd;++pBegin) + { + + OUString aName(getUniqueColumnName(*pBegin)); + Reference< XPropertySet > xColumn; + if(xColumns->hasByName(*pBegin) && (xColumns->getByName(*pBegin) >>= xColumn) && xColumn.is()) + { + OParseColumn* pColumn = new OParseColumn(aName + , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME))) + , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE))) + , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION))) + , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE))) + , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))) + , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))) + , getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))) + , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))) + , getBOOL(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY))) + , isCaseSensitive() + , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME))) + , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME))) + , getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME)))); + + pColumn->setTableName(_rTableAlias); + pColumn->setRealName(*pBegin); + Reference< XPropertySet> xCol = pColumn; + _rColumns->push_back(xCol); + } + else + impl_appendError( IParseContext::ErrorCode::InvalidColumn, pBegin, &_rTableAlias ); + } +} + +void OSQLParseTreeIterator::setSelectColumnName(::rtl::Reference<OSQLColumns> const & _rColumns,const OUString & rColumnName,const OUString & rColumnAlias, const OUString & rTableRange, bool bFkt, sal_Int32 _nType, bool bAggFkt) +{ + if(rColumnName.toChar() == '*' && rTableRange.isEmpty()) + { // SELECT * ... + OSL_ENSURE(_rColumns == m_aSelectColumns,"Invalid columns used here!"); + for (auto const& table : *m_pImpl->m_pTables) + appendColumns(_rColumns,table.first,table.second); + } + else if( rColumnName.toChar() == '*' && !rTableRange.isEmpty() ) + { // SELECT <table>.* + OSL_ENSURE(_rColumns == m_aSelectColumns,"Invalid columns used here!"); + OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange); + + if(aFind != m_pImpl->m_pTables->end()) + appendColumns(_rColumns,rTableRange,aFind->second); + } + else if ( rTableRange.isEmpty() ) + { // SELECT <something> ... + // without table specified + if ( !bFkt ) + { + Reference< XPropertySet> xNewColumn; + + for (auto const& table : *m_pImpl->m_pTables) + { + if ( !table.second.is() ) + continue; + + Reference<XNameAccess> xColumns = table.second->getColumns(); + Reference< XPropertySet > xColumn; + if ( !xColumns->hasByName( rColumnName ) + || !( xColumns->getByName( rColumnName ) >>= xColumn ) + ) + continue; + + OUString aNewColName(getUniqueColumnName(rColumnAlias)); + + OParseColumn* pColumn = new OParseColumn(xColumn,isCaseSensitive()); + xNewColumn = pColumn; + pColumn->setTableName(table.first); + pColumn->setName(aNewColName); + pColumn->setRealName(rColumnName); + + break; + } + + if ( !xNewColumn.is() ) + { + // no function (due to the above !bFkt), no existing column + // => assume an expression + OUString aNewColName( getUniqueColumnName( rColumnAlias ) ); + // did not find a column with this name in any of the tables + OParseColumn* pColumn = new OParseColumn( + aNewColName, + "VARCHAR", + // TODO: does this match with _nType? + // Or should be fill this from the getTypeInfo of the connection? + OUString(), + OUString(), + ColumnValue::NULLABLE_UNKNOWN, + 0, + 0, + _nType, + false, + false, + isCaseSensitive(), + OUString(), + OUString(), + OUString() + ); + + xNewColumn = pColumn; + pColumn->setRealName( rColumnName ); + } + + _rColumns->push_back( xNewColumn ); + } + else + { + OUString aNewColName(getUniqueColumnName(rColumnAlias)); + + OParseColumn* pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(), + ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(), + OUString(),OUString(),OUString()); + pColumn->setFunction(true); + pColumn->setAggregateFunction(bAggFkt); + pColumn->setRealName(rColumnName); + + Reference< XPropertySet> xCol = pColumn; + _rColumns->push_back(xCol); + } + } + else // ColumnName and TableName exist + { + OSQLTables::const_iterator aFind = m_pImpl->m_pTables->find(rTableRange); + + bool bError = false; + if (aFind != m_pImpl->m_pTables->end() && aFind->second.is()) + { + if (bFkt) + { + OUString aNewColName(getUniqueColumnName(rColumnAlias)); + + OParseColumn* pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(), + ColumnValue::NULLABLE_UNKNOWN,0,0,_nType,false,false,isCaseSensitive(), + OUString(),OUString(),OUString()); + pColumn->setFunction(true); + pColumn->setAggregateFunction(bAggFkt); + pColumn->setRealName(rColumnName); + SAL_WARN("connectivity.parse", "Trying to construct a column with Function==true and a TableName; this makes no sense."); + assert(false); + pColumn->setTableName(aFind->first); + + Reference< XPropertySet> xCol = pColumn; + _rColumns->push_back(xCol); + } + else + { + Reference< XPropertySet > xColumn; + if (aFind->second->getColumns()->hasByName(rColumnName) && (aFind->second->getColumns()->getByName(rColumnName) >>= xColumn)) + { + OUString aNewColName(getUniqueColumnName(rColumnAlias)); + + OParseColumn* pColumn = new OParseColumn(xColumn,isCaseSensitive()); + pColumn->setName(aNewColName); + pColumn->setRealName(rColumnName); + pColumn->setTableName(aFind->first); + + Reference< XPropertySet> xCol = pColumn; + _rColumns->push_back(xCol); + } + else + bError = true; + } + } + else + bError = true; + + // Table does not exist or lacking field + if (bError) + { + OUString aNewColName(getUniqueColumnName(rColumnAlias)); + + OParseColumn* pColumn = new OParseColumn(aNewColName,OUString(),OUString(),OUString(), + ColumnValue::NULLABLE_UNKNOWN,0,0,DataType::VARCHAR,false,false,isCaseSensitive(), + OUString(),OUString(),OUString()); + pColumn->setFunction(true); + pColumn->setAggregateFunction(bAggFkt); + + Reference< XPropertySet> xCol = pColumn; + _rColumns->push_back(xCol); + } + } +} + +OUString OSQLParseTreeIterator::getUniqueColumnName(const OUString & rColumnName) const +{ + OUString aAlias(rColumnName); + + OSQLColumns::const_iterator aIter = find( + m_aSelectColumns->begin(), + m_aSelectColumns->end(), + aAlias, + ::comphelper::UStringMixEqual( isCaseSensitive() ) + ); + sal_Int32 i=1; + while(aIter != m_aSelectColumns->end()) + { + aAlias = rColumnName + OUString::number(i++); + aIter = find( + m_aSelectColumns->begin(), + m_aSelectColumns->end(), + aAlias, + ::comphelper::UStringMixEqual( isCaseSensitive() ) + ); + } + return aAlias; +} + +void OSQLParseTreeIterator::setOrderByColumnName(const OUString & rColumnName, OUString & rTableRange, bool bAscending) +{ + Reference<XPropertySet> xColumn = findSelectColumn( rColumnName ); + if ( !xColumn.is() ) + xColumn = findColumn ( rColumnName, rTableRange, false ); + if ( xColumn.is() ) + m_aOrderColumns->push_back(new OOrderColumn( xColumn, rTableRange, isCaseSensitive(), bAscending ) ); + else + { + sal_Int32 nId = rColumnName.toInt32(); + if ( nId > 0 && nId < static_cast<sal_Int32>(m_aSelectColumns->size()) ) + m_aOrderColumns->push_back( new OOrderColumn( (*m_aSelectColumns)[nId-1], isCaseSensitive(), bAscending ) ); + } + +#ifdef SQL_TEST_PARSETREEITERATOR + cout << "OSQLParseTreeIterator::setOrderByColumnName: " + << (const char *) rColumnName << ", " + << (const char *) rTableRange << ", " + << (bAscending ? "true" : "false") + << "\n"; +#endif +} + +void OSQLParseTreeIterator::setGroupByColumnName(const OUString & rColumnName, OUString & rTableRange) +{ + Reference<XPropertySet> xColumn = findColumn( rColumnName, rTableRange, false ); + if ( xColumn.is() ) + m_aGroupColumns->push_back(new OParseColumn(xColumn,isCaseSensitive())); + else + { + sal_Int32 nId = rColumnName.toInt32(); + if ( nId > 0 && nId < static_cast<sal_Int32>(m_aSelectColumns->size()) ) + m_aGroupColumns->push_back(new OParseColumn((*m_aSelectColumns)[nId-1],isCaseSensitive())); + } + +#ifdef SQL_TEST_PARSETREEITERATOR + cout << "OSQLParseTreeIterator::setGroupByColumnName: " + << (const char *) rColumnName << ", " + << (const char *) rTableRange << ", " + << (bAscending ? "true" : "false") + << "\n"; +#endif +} + + +const OSQLParseNode* OSQLParseTreeIterator::getWhereTree() const +{ + if (!m_pParseTree) + return nullptr; + + // Analyse parse tree (depending on statement type) + // and set pointer to WHERE clause: + OSQLParseNode * pWhereClause = nullptr; + if(getStatementType() == OSQLStatementType::Select) + { + OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!"); + OSQLParseNode * pTableExp = m_pParseTree->getChild(3); + OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); + + pWhereClause = pTableExp->getChild(1); + } + else if (SQL_ISRULE(m_pParseTree,update_statement_searched) || + SQL_ISRULE(m_pParseTree,delete_statement_searched)) + { + pWhereClause = m_pParseTree->getChild(m_pParseTree->count()-1); + } + if(pWhereClause && pWhereClause->count() != 2) + pWhereClause = nullptr; + return pWhereClause; +} + + +const OSQLParseNode* OSQLParseTreeIterator::getOrderTree() const +{ + if (!m_pParseTree || getStatementType() != OSQLStatementType::Select) + return nullptr; + + // Analyse parse tree (depending on statement type) + // and set pointer to ORDER clause: + OSQLParseNode * pOrderClause = nullptr; + OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!"); + OSQLParseNode * pTableExp = m_pParseTree->getChild(3); + OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); + + pOrderClause = pTableExp->getChild(ORDER_BY_CHILD_POS); + // If it is an order_by, it must not be empty + if(pOrderClause->count() != 3) + pOrderClause = nullptr; + return pOrderClause; +} + +const OSQLParseNode* OSQLParseTreeIterator::getGroupByTree() const +{ + if (!m_pParseTree || getStatementType() != OSQLStatementType::Select) + return nullptr; + + // Analyse parse tree (depending on statement type) + // and set pointer to ORDER clause: + OSQLParseNode * pGroupClause = nullptr; + OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!"); + OSQLParseNode * pTableExp = m_pParseTree->getChild(3); + OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); + + pGroupClause = pTableExp->getChild(2); + // If it is an order_by, it must not be empty + if(pGroupClause->count() != 3) + pGroupClause = nullptr; + return pGroupClause; +} + +const OSQLParseNode* OSQLParseTreeIterator::getHavingTree() const +{ + if (!m_pParseTree || getStatementType() != OSQLStatementType::Select) + return nullptr; + + // Analyse parse tree (depending on statement type) + // and set pointer to ORDER clause: + OSQLParseNode * pHavingClause = nullptr; + OSL_ENSURE(m_pParseTree->count() >= 4,"ParseTreeIterator: error in parse tree!"); + OSQLParseNode * pTableExp = m_pParseTree->getChild(3); + OSL_ENSURE(pTableExp != nullptr,"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(SQL_ISRULE(pTableExp,table_exp),"OSQLParseTreeIterator: error in parse tree!"); + OSL_ENSURE(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"OSQLParseTreeIterator: error in parse tree!"); + + pHavingClause = pTableExp->getChild(3); + // If it is an order_by, then it must not be empty + if(pHavingClause->count() < 1) + pHavingClause = nullptr; + return pHavingClause; +} + +bool OSQLParseTreeIterator::isTableNode(const OSQLParseNode* _pTableNode) +{ + return _pTableNode && (SQL_ISRULE(_pTableNode,catalog_name) || + SQL_ISRULE(_pTableNode,schema_name) || + SQL_ISRULE(_pTableNode,table_name)); +} + +const OSQLParseNode* OSQLParseTreeIterator::getSimpleWhereTree() const +{ + const OSQLParseNode* pNode = getWhereTree(); + return pNode ? pNode->getChild(1) : nullptr; +} + +const OSQLParseNode* OSQLParseTreeIterator::getSimpleOrderTree() const +{ + const OSQLParseNode* pNode = getOrderTree(); + return pNode ? pNode->getChild(2) : nullptr; +} + +const OSQLParseNode* OSQLParseTreeIterator::getSimpleGroupByTree() const +{ + const OSQLParseNode* pNode = getGroupByTree(); + return pNode ? pNode->getChild(2) : nullptr; +} + +const OSQLParseNode* OSQLParseTreeIterator::getSimpleHavingTree() const +{ + const OSQLParseNode* pNode = getHavingTree(); + return pNode ? pNode->getChild(1) : nullptr; +} + + +Reference< XPropertySet > OSQLParseTreeIterator::findSelectColumn( const OUString & rColumnName ) +{ + for (auto const& lookupColumn : *m_aSelectColumns) + { + Reference< XPropertySet > xColumn( lookupColumn ); + try + { + OUString sName; + xColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_NAME ) ) >>= sName; + if ( sName == rColumnName ) + return xColumn; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.parse"); + } + } + return nullptr; +} + + +Reference< XPropertySet > OSQLParseTreeIterator::findColumn( const OUString & rColumnName, OUString & rTableRange, bool _bLookInSubTables ) +{ + Reference< XPropertySet > xColumn = findColumn( *m_pImpl->m_pTables, rColumnName, rTableRange ); + if ( !xColumn.is() && _bLookInSubTables ) + xColumn = findColumn( *m_pImpl->m_pSubTables, rColumnName, rTableRange ); + return xColumn; +} + + +Reference< XPropertySet > OSQLParseTreeIterator::findColumn(const OSQLTables& _rTables, const OUString & rColumnName, OUString & rTableRange) +{ + Reference< XPropertySet > xColumn; + if ( !rTableRange.isEmpty() ) + { + OSQLTables::const_iterator aFind = _rTables.find(rTableRange); + + if ( aFind != _rTables.end() + && aFind->second.is() + && aFind->second->getColumns().is() + && aFind->second->getColumns()->hasByName(rColumnName) ) + aFind->second->getColumns()->getByName(rColumnName) >>= xColumn; + } + if ( !xColumn.is() ) + { + for (auto const& table : _rTables) + { + if ( table.second.is() ) + { + Reference<XNameAccess> xColumns = table.second->getColumns(); + if( xColumns.is() && xColumns->hasByName(rColumnName) && (xColumns->getByName(rColumnName) >>= xColumn) ) + { + OSL_ENSURE(xColumn.is(),"Column isn't a propertyset!"); + // Cannot take "rTableRange = table.first" because that is the fully composed name + // that is, catalogName.schemaName.tableName + rTableRange = getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME))); + break; // This column must only exits once + } + } + } + } + return xColumn; +} + + +void OSQLParseTreeIterator::impl_appendError( IParseContext::ErrorCode _eError, const OUString* _pReplaceToken1, const OUString* _pReplaceToken2 ) +{ + OUString sErrorMessage = m_rParser.getContext().getErrorMessage( _eError ); + if ( _pReplaceToken1 ) + { + bool bTwoTokens = ( _pReplaceToken2 != nullptr ); + const char* pPlaceHolder1 = bTwoTokens ? "#1" : "#"; + const OUString sPlaceHolder1 = OUString::createFromAscii( pPlaceHolder1 ); + + sErrorMessage = sErrorMessage.replaceFirst( sPlaceHolder1, *_pReplaceToken1 ); + if ( _pReplaceToken2 ) + sErrorMessage = sErrorMessage.replaceFirst( "#2" , *_pReplaceToken2 ); + } + + impl_appendError( SQLException( + sErrorMessage, nullptr, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() ) ); +} + + +void OSQLParseTreeIterator::impl_appendError( const SQLException& _rError ) +{ + SAL_WARN("connectivity.parse", "Adding error " << exceptionToString(Any(_rError))); + if ( m_xErrors ) + { + SQLException* pErrorChain = &*m_xErrors; + while ( pErrorChain->NextException.hasValue() ) + pErrorChain = static_cast< SQLException* >( pErrorChain->NextException.pData ); + pErrorChain->NextException <<= _rError; + } + else + m_xErrors = _rError; +} + +sal_Int32 OSQLParseTreeIterator::getFunctionReturnType(const OSQLParseNode* _pNode ) +{ + sal_Int32 nType = DataType::OTHER; + OUString sFunctionName; + if ( SQL_ISRULE(_pNode,length_exp) ) + { + _pNode->getChild(0)->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false ); + nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() ); + } + else if ( SQL_ISRULE(_pNode,num_value_exp) || SQL_ISRULE(_pNode,term) || SQL_ISRULE(_pNode,factor) ) + { + nType = DataType::DOUBLE; + } + else + { + _pNode->getChild(0)->parseNodeToStr(sFunctionName, m_pImpl->m_xConnection, nullptr, false, false ); + + // MIN and MAX have another return type, we have to check the expression itself. + // @see http://qa.openoffice.org/issues/show_bug.cgi?id=99566 + if ( SQL_ISRULE(_pNode,general_set_fct) && (SQL_ISTOKEN(_pNode->getChild(0),MIN) || SQL_ISTOKEN(_pNode->getChild(0),MAX) )) + { + const OSQLParseNode* pValueExp = _pNode->getChild(3); + if (SQL_ISRULE(pValueExp,column_ref)) + { + OUString sColumnName; + OUString aTableRange; + getColumnRange(pValueExp,sColumnName,aTableRange); + OSL_ENSURE(!sColumnName.isEmpty(),"Columnname must not be empty!"); + Reference<XPropertySet> xColumn = findColumn( sColumnName, aTableRange, true ); + + if ( xColumn.is() ) + { + xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_TYPE)) >>= nType; + } + } + else + { + if ( SQL_ISRULE(pValueExp,num_value_exp) || SQL_ISRULE(pValueExp,term) || SQL_ISRULE(pValueExp,factor) ) + { + nType = DataType::DOUBLE; + } + else if ( SQL_ISRULE(pValueExp,datetime_primary) ) + { + switch(pValueExp->getChild(0)->getTokenID() ) + { + case SQL_TOKEN_CURRENT_DATE: + nType = DataType::DATE; + break; + case SQL_TOKEN_CURRENT_TIME: + nType = DataType::TIME; + break; + case SQL_TOKEN_CURRENT_TIMESTAMP: + nType = DataType::TIMESTAMP; + break; + } + } + else if ( SQL_ISRULE(pValueExp,value_exp_primary) ) + { + nType = getFunctionReturnType(pValueExp->getChild(1)); + } + else if ( SQL_ISRULE(pValueExp,concatenation) + || SQL_ISRULE(pValueExp,char_factor) + || SQL_ISRULE(pValueExp,bit_value_fct) + || SQL_ISRULE(pValueExp,char_value_fct) + || SQL_ISRULE(pValueExp,char_substring_fct) + || SQL_ISRULE(pValueExp,fold) + || SQL_ISTOKEN(pValueExp,STRING) ) + { + nType = DataType::VARCHAR; + } + } + if ( nType == DataType::OTHER ) + nType = DataType::DOUBLE; + } + else + nType = ::connectivity::OSQLParser::getFunctionReturnType( sFunctionName, &m_rParser.getContext() ); + } + + return nType; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/parse/sqlnode.cxx b/connectivity/source/parse/sqlnode.cxx new file mode 100644 index 000000000..d31bcd2a9 --- /dev/null +++ b/connectivity/source/parse/sqlnode.cxx @@ -0,0 +1,2787 @@ +/* -*- 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/macros.h> +#include <connectivity/sqlnode.hxx> +#include <connectivity/sqlerror.hxx> +#include <connectivity/sqlbison_exports.hxx> +#include <connectivity/internalnode.hxx> +#define YYBISON 1 +#include <sqlbison.hxx> +#include <connectivity/sqlparse.hxx> +#include <connectivity/sqlscan.hxx> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/i18n/LocaleData.hpp> +#include <com/sun/star/i18n/NumberFormatIndex.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdb/XQueriesSupplier.hpp> +#include <com/sun/star/sdb/ErrorCondition.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/util/XNumberFormats.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/i18n/KParseType.hpp> +#include <com/sun/star/i18n/KParseTokens.hpp> +#include <com/sun/star/i18n/CharacterClassification.hpp> +#include <connectivity/dbconversion.hxx> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/Date.hpp> +#include <TConnection.hxx> +#include <comphelper/numbers.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbmetadata.hxx> +#include <tools/diagnose_ex.h> +#include <string.h> +#include <algorithm> +#include <functional> +#include <memory> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star; +using namespace ::osl; +using namespace ::dbtools; +using namespace ::comphelper; + +namespace +{ + + bool lcl_saveConvertToNumber(const Reference< XNumberFormatter > & _xFormatter,sal_Int32 _nKey,const OUString& _sValue,double& _nrValue) + { + bool bRet = false; + try + { + _nrValue = _xFormatter->convertStringToNumber(_nKey, _sValue); + bRet = true; + } + catch(Exception&) + { + } + return bRet; + } + + void replaceAndReset(connectivity::OSQLParseNode*& _pResetNode,connectivity::OSQLParseNode* _pNewNode) + { + _pResetNode->getParent()->replace(_pResetNode, _pNewNode); + delete _pResetNode; + _pResetNode = _pNewNode; + } + + /** quotes a string and search for quotes inside the string and replace them with the new quote + @param rValue + The value to be quoted. + @param rQuot + The quote + @param rQuotToReplace + The quote to replace with + @return + The quoted string. + */ + OUString SetQuotation(const OUString& rValue, const OUString& rQuot, const OUString& rQuotToReplace) + { + OUString rNewValue = rQuot + rValue; + sal_Int32 nIndex = sal_Int32(-1); // Replace quotes with double quotes or the parser gets into problems + + if (!rQuot.isEmpty()) + { + do + { + nIndex += 2; + nIndex = rNewValue.indexOf(rQuot,nIndex); + if(nIndex != -1) + rNewValue = rNewValue.replaceAt(nIndex,rQuot.getLength(),rQuotToReplace); + } while (nIndex != -1); + } + + rNewValue += rQuot; + return rNewValue; + } + + bool columnMatchP(const connectivity::OSQLParseNode* pSubTree, const connectivity::SQLParseNodeParameter& rParam) + { + using namespace connectivity; + assert(SQL_ISRULE(pSubTree,column_ref)); + + if(!rParam.xField.is()) + return false; + + // retrieve the field's name & table range + OUString aFieldName; + try + { + sal_Int32 nNamePropertyId = PROPERTY_ID_NAME; + if ( rParam.xField->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_REALNAME ) ) ) + nNamePropertyId = PROPERTY_ID_REALNAME; + rParam.xField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( nNamePropertyId ) ) >>= aFieldName; + } + catch ( Exception& ) + { + } + + if(pSubTree->count()) + { + const OSQLParseNode* pCol = pSubTree->getChild(pSubTree->count()-1); + if (SQL_ISRULE(pCol,column_val)) + { + assert(pCol->count() == 1); + pCol = pCol->getChild(0); + } + const OSQLParseNode* pTable(nullptr); + switch (pSubTree->count()) + { + case 1: + break; + case 3: + pTable = pSubTree->getChild(0); + break; + case 5: + case 7: + SAL_WARN("connectivity.parse", "SQL: catalog and/or schema in column_ref in predicate"); + break; + default: + SAL_WARN("connectivity.parse", "columnMatchP: SQL grammar changed; column_ref has " << pSubTree->count() << " children"); + assert(false); + break; + } + // TODO: not all DBMS match column names case-insensitively... + // see XDatabaseMetaData::supportsMixedCaseIdentifiers() + // and XDatabaseMetaData::supportsMixedCaseQuotedIdentifiers() + if ( // table name matches (or no table name)? + ( !pTable || pTable->getTokenValue().equalsIgnoreAsciiCase(rParam.sPredicateTableAlias) ) + && // column name matches? + pCol->getTokenValue().equalsIgnoreAsciiCase(aFieldName) + ) + return true; + } + return false; + } +} + +namespace connectivity +{ + +SQLParseNodeParameter::SQLParseNodeParameter( const Reference< XConnection >& _rxConnection, + const Reference< XNumberFormatter >& _xFormatter, const Reference< XPropertySet >& _xField, + const OUString &_sPredicateTableAlias, + const Locale& _rLocale, const IParseContext* _pContext, + bool _bIntl, bool _bQuote, OUString _sDecSep, bool _bPredicate, bool _bParseToSDBC ) + :rLocale(_rLocale) + ,aMetaData( _rxConnection ) + ,pParser( nullptr ) + ,pSubQueryHistory( std::make_shared<QueryNameSet>() ) + ,xFormatter(_xFormatter) + ,xField(_xField) + ,sPredicateTableAlias(_sPredicateTableAlias) + ,m_rContext( _pContext ? *_pContext : OSQLParser::s_aDefaultContext ) + ,sDecSep(_sDecSep) + ,bQuote(_bQuote) + ,bInternational(_bIntl) + ,bPredicate(_bPredicate) + ,bParseToSDBCLevel( _bParseToSDBC ) +{ +} + +OUString OSQLParseNode::convertDateString(const SQLParseNodeParameter& rParam, const OUString& rString) +{ + Date aDate = DBTypeConversion::toDate(rString); + Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier()); + Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY); + + double fDate = DBTypeConversion::toDouble(aDate,DBTypeConversion::getNULLDate(xSupplier)); + sal_Int32 nKey = xTypes->getStandardIndex(rParam.rLocale) + 36; // XXX hack + return rParam.xFormatter->convertNumberToString(nKey, fDate); +} + + +OUString OSQLParseNode::convertDateTimeString(const SQLParseNodeParameter& rParam, const OUString& rString) +{ + DateTime aDate = DBTypeConversion::toDateTime(rString); + Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier()); + Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY); + + double fDateTime = DBTypeConversion::toDouble(aDate,DBTypeConversion::getNULLDate(xSupplier)); + sal_Int32 nKey = xTypes->getStandardIndex(rParam.rLocale) + 51; // XXX hack + return rParam.xFormatter->convertNumberToString(nKey, fDateTime); +} + + +OUString OSQLParseNode::convertTimeString(const SQLParseNodeParameter& rParam, const OUString& rString) +{ + css::util::Time aTime = DBTypeConversion::toTime(rString); + Reference< XNumberFormatsSupplier > xSupplier(rParam.xFormatter->getNumberFormatsSupplier()); + + Reference< XNumberFormatTypes > xTypes(xSupplier->getNumberFormats(), UNO_QUERY); + + double fTime = DBTypeConversion::toDouble(aTime); + sal_Int32 nKey = xTypes->getStandardIndex(rParam.rLocale) + 41; // XXX hack + return rParam.xFormatter->convertNumberToString(nKey, fTime); +} + + +void OSQLParseNode::parseNodeToStr(OUString& rString, + const Reference< XConnection >& _rxConnection, + const IParseContext* pContext, + bool _bIntl, + bool _bQuote) const +{ + parseNodeToStr( + rString, _rxConnection, nullptr, nullptr, OUString(), + pContext ? pContext->getPreferredLocale() : OParseContext::getDefaultLocale(), + pContext, _bIntl, _bQuote, OUString("."), false ); +} + + +void OSQLParseNode::parseNodeToPredicateStr(OUString& rString, + const Reference< XConnection >& _rxConnection, + const Reference< XNumberFormatter > & xFormatter, + const css::lang::Locale& rIntl, + OUString _sDec, + const IParseContext* pContext ) const +{ + OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!"); + + if (xFormatter.is()) + parseNodeToStr(rString, _rxConnection, xFormatter, nullptr, OUString(), rIntl, pContext, true, true, _sDec, true); +} + + +void OSQLParseNode::parseNodeToPredicateStr(OUString& rString, + const Reference< XConnection > & _rxConnection, + const Reference< XNumberFormatter > & xFormatter, + const Reference< XPropertySet > & _xField, + const OUString &_sPredicateTableAlias, + const css::lang::Locale& rIntl, + OUString _sDec, + const IParseContext* pContext ) const +{ + OSL_ENSURE(xFormatter.is(), "OSQLParseNode::parseNodeToPredicateStr:: no formatter!"); + + if (xFormatter.is()) + parseNodeToStr( rString, _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext, true, true, _sDec, true ); +} + + +void OSQLParseNode::parseNodeToStr(OUString& rString, + const Reference< XConnection > & _rxConnection, + const Reference< XNumberFormatter > & xFormatter, + const Reference< XPropertySet > & _xField, + const OUString &_sPredicateTableAlias, + const css::lang::Locale& rIntl, + const IParseContext* pContext, + bool _bIntl, + bool _bQuote, + OUString _sDecSep, + bool _bPredicate) const +{ + OSL_ENSURE( _rxConnection.is(), "OSQLParseNode::parseNodeToStr: invalid connection!" ); + + if ( !_rxConnection.is() ) + return; + + OUStringBuffer sBuffer = rString; + try + { + OSQLParseNode::impl_parseNodeToString_throw( sBuffer, + SQLParseNodeParameter( + _rxConnection, xFormatter, _xField, _sPredicateTableAlias, rIntl, pContext, + _bIntl, _bQuote, _sDecSep, _bPredicate, false + ) ); + } + catch( const SQLException& ) + { + SAL_WARN( "connectivity.parse", "OSQLParseNode::parseNodeToStr: this should not throw!" ); + // our callers don't expect this method to throw anything. The only known situation + // where impl_parseNodeToString_throw can throw is when there is a cyclic reference + // in the sub queries, but this cannot be the case here, as we do not parse to + // SDBC level. + } + rString = sBuffer.makeStringAndClear(); +} + +bool OSQLParseNode::parseNodeToExecutableStatement( OUString& _out_rString, const Reference< XConnection >& _rxConnection, + OSQLParser& _rParser, css::sdbc::SQLException* _pErrorHolder ) const +{ + OSL_PRECOND( _rxConnection.is(), "OSQLParseNode::parseNodeToExecutableStatement: invalid connection!" ); + SQLParseNodeParameter aParseParam( _rxConnection, + nullptr, nullptr, OUString(), OParseContext::getDefaultLocale(), nullptr, false, true, OUString("."), false, true ); + + if ( aParseParam.aMetaData.supportsSubqueriesInFrom() ) + { + Reference< XQueriesSupplier > xSuppQueries( _rxConnection, UNO_QUERY ); + OSL_ENSURE( xSuppQueries.is(), "OSQLParseNode::parseNodeToExecutableStatement: cannot substitute everything without a QueriesSupplier!" ); + if ( xSuppQueries.is() ) + aParseParam.xQueries = xSuppQueries->getQueries(); + } + + aParseParam.pParser = &_rParser; + + // LIMIT keyword differs in Firebird + OSQLParseNode* pTableExp = getChild(3); + Reference< XDatabaseMetaData > xMeta( _rxConnection->getMetaData() ); + OUString sLimitValue; + if( pTableExp->getChild(6)->count() >= 2 && pTableExp->getChild(6)->getChild(1) + && (xMeta->getURL().equalsIgnoreAsciiCase("sdbc:embedded:firebird") + || xMeta->getURL().startsWithIgnoreAsciiCase("sdbc:firebird:"))) + { + sLimitValue = pTableExp->getChild(6)->getChild(1)->getTokenValue(); + pTableExp->removeAt(6); + } + + _out_rString.clear(); + OUStringBuffer sBuffer; + bool bSuccess = false; + try + { + impl_parseNodeToString_throw( sBuffer, aParseParam ); + bSuccess = true; + } + catch( const SQLException& e ) + { + if ( _pErrorHolder ) + *_pErrorHolder = e; + } + + if(sLimitValue.getLength() > 0) + { + constexpr char SELECT_KEYWORD[] = "SELECT"; + sBuffer.insert(sBuffer.indexOf(SELECT_KEYWORD) + strlen(SELECT_KEYWORD), + " FIRST " + sLimitValue); + } + + _out_rString = sBuffer.makeStringAndClear(); + return bSuccess; +} + + +namespace +{ + bool lcl_isAliasNamePresent( const OSQLParseNode& _rTableNameNode ) + { + return !OSQLParseNode::getTableRange(_rTableNameNode.getParent()).isEmpty(); + } +} + + +void OSQLParseNode::impl_parseNodeToString_throw(OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple) const +{ + if ( isToken() ) + { + parseLeaf(rString,rParam); + return; + } + + // Lets see how many nodes this subtree has + sal_uInt32 nCount = count(); + + bool bHandled = false; + switch ( getKnownRuleID() ) + { + // special handling for parameters + case parameter: + { + bSimple=false; + if(!rString.isEmpty()) + rString.append(" "); + if (nCount == 1) // ? + m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false ); + else if (rParam.bParseToSDBCLevel && rParam.aMetaData.shouldSubstituteParameterNames()) + { + rString.append("?"); + } + else if (nCount == 2) // :Name + { + m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false ); + rString.append(m_aChildren[1]->m_aNodeValue); + } // [Name] + else + { + assert (nCount == 3); + m_aChildren[0]->impl_parseNodeToString_throw( rString, rParam, false ); + rString.append(m_aChildren[1]->m_aNodeValue); + rString.append(m_aChildren[2]->m_aNodeValue); + } + bHandled = true; + } + break; + + // table refs + case table_ref: + bSimple=false; + if ( ( nCount == 2 ) || ( nCount == 3 ) || ( nCount == 5 ) ) + { + impl_parseTableRangeNodeToString_throw( rString, rParam ); + bHandled = true; + } + break; + + // table name - might be a query name + case table_name: + bSimple=false; + bHandled = impl_parseTableNameNodeToString_throw( rString, rParam ); + break; + + case as_clause: + bSimple=false; + assert(nCount == 0 || nCount == 2); + if (nCount == 2) + { + if ( rParam.aMetaData.generateASBeforeCorrelationName() ) + rString.append(" AS "); + m_aChildren[1]->impl_parseNodeToString_throw( rString, rParam, false ); + } + bHandled = true; + break; + + case opt_as: + assert(nCount == 0); + bHandled = true; + break; + + case like_predicate: + // Depending on whether international is given, LIKE is treated differently + // international: *, ? are placeholders + // else SQL92 conform: %, _ + impl_parseLikeNodeToString_throw( rString, rParam, bSimple ); + bHandled = true; + break; + + case general_set_fct: + case set_fct_spec: + case position_exp: + case extract_exp: + case length_exp: + case char_value_fct: + bSimple=false; + if (!addDateValue(rString, rParam)) + { + // Do not quote function name + SQLParseNodeParameter aNewParam(rParam); + aNewParam.bQuote = ( SQL_ISRULE(this,length_exp) || SQL_ISRULE(this,char_value_fct) ); + + m_aChildren[0]->impl_parseNodeToString_throw( rString, aNewParam, false ); + aNewParam.bQuote = rParam.bQuote; + //aNewParam.bPredicate = sal_False; // disable [ ] around names // look at i73215 + OUStringBuffer aStringPara; + for (sal_uInt32 i=1; i<nCount; i++) + { + const OSQLParseNode * pSubTree = m_aChildren[i].get(); + if (pSubTree) + { + pSubTree->impl_parseNodeToString_throw( aStringPara, aNewParam, false ); + + // In the comma lists, put commas in-between all subtrees + if ((m_eNodeType == SQLNodeType::CommaListRule) && (i < (nCount - 1))) + aStringPara.append(","); + } + else + i++; + } + rString.append(aStringPara.makeStringAndClear()); + } + bHandled = true; + break; + case odbc_call_spec: + case subquery: + case term: + case factor: + case window_function: + case cast_spec: + case num_value_exp: + bSimple = false; + break; + default: + break; + } // switch ( getKnownRuleID() ) + + if ( bHandled ) + return; + + for (auto i = m_aChildren.begin(); i != m_aChildren.end();) + { + const OSQLParseNode* pSubTree = i->get(); + if ( !pSubTree ) + { + ++i; + continue; + } + + SQLParseNodeParameter aNewParam(rParam); + + // don't replace the field for subqueries + if (rParam.xField.is() && SQL_ISRULE(pSubTree,subquery)) + aNewParam.xField = nullptr; + + // When we are building a criterion inside a query view, + // simplify criterion display by removing: + // "currentFieldName" + // "currentFieldName" = + // but only in simple expressions. + // This means anything that is made of: + // (see the rules conditionalised by inPredicateCheck() in sqlbison.y). + // - parentheses + // - logical operators (and, or, not) + // - comparison operators (IS, =, >, <, BETWEEN, LIKE, ...) + // but *not* e.g. in function arguments + if (bSimple && rParam.bPredicate && rParam.xField.is() && SQL_ISRULE(pSubTree,column_ref)) + { + if (columnMatchP(pSubTree, rParam)) + { + // skip field + ++i; + // if the following node is the comparison operator'=', + // we filter it as well + if (SQL_ISRULE(this, comparison_predicate)) + { + if(i != m_aChildren.end()) + { + pSubTree = i->get(); + if (pSubTree && pSubTree->getNodeType() == SQLNodeType::Equal) + ++i; + } + } + } + else + { + pSubTree->impl_parseNodeToString_throw( rString, aNewParam, bSimple ); + ++i; + + // In the comma lists, put commas in-between all subtrees + if ((m_eNodeType == SQLNodeType::CommaListRule) && (i != m_aChildren.end())) + rString.append(","); + } + } + else + { + pSubTree->impl_parseNodeToString_throw( rString, aNewParam, bSimple ); + ++i; + + // In the comma lists, put commas in-between all subtrees + if ((m_eNodeType == SQLNodeType::CommaListRule) && (i != m_aChildren.end())) + { + if (SQL_ISRULE(this,value_exp_commalist) && rParam.bPredicate) + rString.append(";"); + else + rString.append(","); + } + } + // The right hand-side of these operators is not simple + switch ( getKnownRuleID() ) + { + case general_set_fct: + case set_fct_spec: + case position_exp: + case extract_exp: + case length_exp: + case char_value_fct: + case odbc_call_spec: + case subquery: + case comparison_predicate: + case between_predicate: + case like_predicate: + case test_for_null: + case in_predicate: + case existence_test: + case unique_test: + case all_or_any_predicate: + case join_condition: + case comparison_predicate_part_2: + case parenthesized_boolean_value_expression: + case other_like_predicate_part_2: + case between_predicate_part_2: + bSimple=false; + break; + default: + break; + } + } +} + + +bool OSQLParseNode::impl_parseTableNameNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam ) const +{ + // is the table_name part of a table_ref? + OSL_ENSURE( getParent(), "OSQLParseNode::impl_parseTableNameNodeToString_throw: table_name without parent?" ); + if ( !getParent() || ( getParent()->getKnownRuleID() != table_ref ) ) + return false; + + // if it's a query, maybe we need to substitute the SQL statement ... + if ( !rParam.bParseToSDBCLevel ) + return false; + + if ( !rParam.xQueries.is() ) + // connection does not support queries in queries, or was no query supplier + return false; + + try + { + OUString sTableOrQueryName( getChild(0)->getTokenValue() ); + bool bIsQuery = rParam.xQueries->hasByName( sTableOrQueryName ); + if ( !bIsQuery ) + return false; + + // avoid recursion (e.g. "foo" defined as "SELECT * FROM bar" and "bar" defined as "SELECT * FROM foo". + if ( rParam.pSubQueryHistory->find( sTableOrQueryName ) != rParam.pSubQueryHistory->end() ) + { + OSL_ENSURE( rParam.pParser, "OSQLParseNode::impl_parseTableNameNodeToString_throw: no parser?" ); + if ( rParam.pParser ) + { + const SQLError& rErrors( rParam.pParser->getErrorHelper() ); + rErrors.raiseException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES ); + } + else + { + SQLError aErrors; + aErrors.raiseException( sdb::ErrorCondition::PARSER_CYCLIC_SUB_QUERIES ); + } + } + rParam.pSubQueryHistory->insert( sTableOrQueryName ); + + Reference< XPropertySet > xQuery( rParam.xQueries->getByName( sTableOrQueryName ), UNO_QUERY_THROW ); + + // substitute the query name with the constituting command + OUString sCommand; + OSL_VERIFY( xQuery->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_COMMAND ) ) >>= sCommand ); + + bool bEscapeProcessing = false; + OSL_VERIFY( xQuery->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex( PROPERTY_ID_ESCAPEPROCESSING ) ) >>= bEscapeProcessing ); + + // the query we found here might itself be based on another query, so parse it recursively + OSL_ENSURE( rParam.pParser, "OSQLParseNode::impl_parseTableNameNodeToString_throw: cannot analyze sub queries without a parser!" ); + if ( bEscapeProcessing && rParam.pParser ) + { + OUString sError; + std::unique_ptr< OSQLParseNode > pSubQueryNode( rParam.pParser->parseTree( sError, sCommand ) ); + if (pSubQueryNode) + { + // parse the sub-select to SDBC level, too + OUStringBuffer sSubSelect; + pSubQueryNode->impl_parseNodeToString_throw( sSubSelect, rParam, false ); + if ( !sSubSelect.isEmpty() ) + sCommand = sSubSelect.makeStringAndClear(); + } + } + + rString.append( " ( " ); + rString.append(sCommand); + rString.append( " )" ); + + // append the query name as table alias, since it might be referenced in other + // parts of the statement - but only if there's no other alias name present + if ( !lcl_isAliasNamePresent( *this ) ) + { + rString.append( " AS " ); + if ( rParam.bQuote ) + rString.append(SetQuotation( sTableOrQueryName, + rParam.aMetaData.getIdentifierQuoteString(), rParam.aMetaData.getIdentifierQuoteString() )); + } + + // don't forget to remove the query name from the history, else multiple inclusions + // won't work + // #i69227# / 2006-10-10 / frank.schoenheit@sun.com + rParam.pSubQueryHistory->erase( sTableOrQueryName ); + + return true; + } + catch( const SQLException& ) + { + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("connectivity.parse"); + } + return false; +} + + +void OSQLParseNode::impl_parseTableRangeNodeToString_throw(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const +{ + OSL_PRECOND( ( count() == 2 ) || ( count() == 3 ) || ( count() == 5 ) ,"Illegal count"); + + // rString += " "; + std::for_each(m_aChildren.begin(),m_aChildren.end(), + [&] (std::unique_ptr<OSQLParseNode> const & pNode) { pNode->impl_parseNodeToString_throw(rString, rParam, false); }); +} + + +void OSQLParseNode::impl_parseLikeNodeToString_throw( OUStringBuffer& rString, const SQLParseNodeParameter& rParam, bool bSimple ) const +{ + assert(SQL_ISRULE(this,like_predicate)); + OSL_ENSURE(count() == 2,"count != 2: Prepare for GPF"); + + const OSQLParseNode* pEscNode = nullptr; + const OSQLParseNode* pParaNode = nullptr; + + SQLParseNodeParameter aNewParam(rParam); + //aNewParam.bQuote = sal_True; // why setting this to true? @see https://bz.apache.org/ooo/show_bug.cgi?id=75557 + + if ( !(bSimple && rParam.bPredicate && rParam.xField.is() && SQL_ISRULE(m_aChildren[0],column_ref) && columnMatchP(m_aChildren[0].get(), rParam)) ) + m_aChildren[0]->impl_parseNodeToString_throw( rString, aNewParam, bSimple ); + + const OSQLParseNode* pPart2 = m_aChildren[1].get(); + pPart2->getChild(0)->impl_parseNodeToString_throw( rString, aNewParam, false ); + pPart2->getChild(1)->impl_parseNodeToString_throw( rString, aNewParam, false ); + pParaNode = pPart2->getChild(2); + pEscNode = pPart2->getChild(3); + + if (pParaNode->isToken()) + { + OUString aStr = ConvertLikeToken(pParaNode, pEscNode, rParam.bInternational); + rString.append(" "); + rString.append(SetQuotation(aStr,"\'","\'\'")); + } + else + pParaNode->impl_parseNodeToString_throw( rString, aNewParam, false ); + + pEscNode->impl_parseNodeToString_throw( rString, aNewParam, false ); +} + + +bool OSQLParseNode::getTableComponents(const OSQLParseNode* _pTableNode, + css::uno::Any &_rCatalog, + OUString &_rSchema, + OUString &_rTable, + const Reference< XDatabaseMetaData >& _xMetaData) +{ + OSL_ENSURE(_pTableNode,"Wrong use of getTableComponents! _pTableNode is not allowed to be null!"); + if(_pTableNode) + { + const bool bSupportsCatalog = _xMetaData.is() && _xMetaData->supportsCatalogsInDataManipulation(); + const bool bSupportsSchema = _xMetaData.is() && _xMetaData->supportsSchemasInDataManipulation(); + const OSQLParseNode* pTableNode = _pTableNode; + // clear the parameter given + _rCatalog = Any(); + _rSchema.clear(); + _rTable.clear(); + // see rule catalog_name: in sqlbison.y + if (SQL_ISRULE(pTableNode,catalog_name)) + { + OSL_ENSURE(pTableNode->getChild(0) && pTableNode->getChild(0)->isToken(),"Invalid parsenode!"); + _rCatalog <<= pTableNode->getChild(0)->getTokenValue(); + pTableNode = pTableNode->getChild(2); + } + // check if we have schema_name rule + if(SQL_ISRULE(pTableNode,schema_name)) + { + if ( bSupportsCatalog && !bSupportsSchema ) + _rCatalog <<= pTableNode->getChild(0)->getTokenValue(); + else + _rSchema = pTableNode->getChild(0)->getTokenValue(); + pTableNode = pTableNode->getChild(2); + } + // check if we have table_name rule + if(SQL_ISRULE(pTableNode,table_name)) + { + _rTable = pTableNode->getChild(0)->getTokenValue(); + } + else + { + SAL_WARN( "connectivity.parse","Error in parse tree!"); + } + } + return !_rTable.isEmpty(); +} + +void OSQLParser::killThousandSeparator(OSQLParseNode* pLiteral) +{ + if ( pLiteral ) + { + if ( s_xLocaleData->getLocaleItem( m_pData->aLocale ).decimalSeparator.toChar() == ',' ) + { + pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace('.', sal_Unicode()); + // and replace decimal + pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace(',', '.'); + } + else + pLiteral->m_aNodeValue = pLiteral->m_aNodeValue.replace(',', sal_Unicode()); + } +} + +OSQLParseNode* OSQLParser::convertNode(sal_Int32 nType, OSQLParseNode* pLiteral) +{ + if ( !pLiteral ) + return nullptr; + + OSQLParseNode* pReturn = pLiteral; + + if ( ( pLiteral->isRule() && !SQL_ISRULE(pLiteral,value_exp) ) || SQL_ISTOKEN(pLiteral,FALSE) || SQL_ISTOKEN(pLiteral,TRUE) ) + { + switch(nType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CLOB: + if ( !SQL_ISRULE(pReturn,char_value_exp) && !buildStringNodes(pReturn) ) + pReturn = nullptr; + break; + default: + break; + } + } + else + { + switch(pLiteral->getNodeType()) + { + case SQLNodeType::String: + switch(nType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CLOB: + break; + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + if (m_xFormatter.is()) + pReturn = buildDate( nType, pReturn); + break; + default: + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare); + break; + } + break; + case SQLNodeType::AccessDate: + switch(nType) + { + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + if ( m_xFormatter.is() ) + pReturn = buildDate( nType, pReturn); + else + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidDateCompare); + break; + default: + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidCompare); + break; + } + break; + case SQLNodeType::IntNum: + switch(nType) + { + case DataType::BIT: + case DataType::BOOLEAN: + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + case DataType::BIGINT: + case DataType::FLOAT: + case DataType::REAL: + case DataType::DOUBLE: + // kill thousand separators if any + killThousandSeparator(pReturn); + break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CLOB: + pReturn = buildNode_STR_NUM(pReturn); + break; + default: + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidIntCompare); + break; + } + break; + case SQLNodeType::ApproxNum: + switch(nType) + { + case DataType::DECIMAL: + case DataType::NUMERIC: + case DataType::FLOAT: + case DataType::REAL: + case DataType::DOUBLE: + // kill thousand separators if any + killThousandSeparator(pReturn); + break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CLOB: + pReturn = buildNode_STR_NUM(pReturn); + break; + case DataType::INTEGER: + default: + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidRealCompare); + break; + } + break; + default: + ; + } + } + return pReturn; +} + +sal_Int16 OSQLParser::buildPredicateRule(OSQLParseNode*& pAppend, OSQLParseNode* pLiteral, OSQLParseNode* pCompare, OSQLParseNode* pLiteral2) +{ + OSL_ENSURE(inPredicateCheck(),"Only in predicate check allowed!"); + sal_Int16 nErg = 0; + if ( m_xField.is() ) + { + sal_Int32 nType = 0; + try + { + m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType; + } + catch( Exception& ) + { + return nErg; + } + + OSQLParseNode* pNode1 = convertNode(nType,pLiteral); + if ( pNode1 ) + { + OSQLParseNode* pNode2 = convertNode(nType,pLiteral2); + if ( m_sErrorMessage.isEmpty() ) + nErg = buildNode(pAppend,pCompare,pNode1,pNode2); + } + } + if (!pCompare->getParent()) // I have no parent so I was not used and I must die :-) + delete pCompare; + return nErg; +} + +sal_Int16 OSQLParser::buildLikeRule(OSQLParseNode* pAppend, OSQLParseNode*& pLiteral, const OSQLParseNode* pEscape) +{ + sal_Int16 nErg = 0; + sal_Int32 nType = 0; + + if (!m_xField.is()) + return nErg; + try + { + Any aValue; + { + aValue = m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)); + aValue >>= nType; + } + } + catch( Exception& ) + { + return nErg; + } + + switch (nType) + { + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CLOB: + if(pLiteral->isRule()) + { + pAppend->append(pLiteral); + nErg = 1; + } + else + { + switch(pLiteral->getNodeType()) + { + case SQLNodeType::String: + pLiteral->m_aNodeValue = ConvertLikeToken(pLiteral, pEscape, false); + pAppend->append(pLiteral); + nErg = 1; + break; + case SQLNodeType::ApproxNum: + if (m_xFormatter.is() && m_nFormatKey) + { + sal_Int16 nScale = 0; + try + { + Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, "Decimals" ); + aValue >>= nScale; + } + catch( Exception& ) + { + } + + pAppend->append(new OSQLInternalNode(stringToDouble(pLiteral->getTokenValue(),nScale),SQLNodeType::String)); + } + else + pAppend->append(new OSQLInternalNode(pLiteral->getTokenValue(),SQLNodeType::String)); + + delete pLiteral; + nErg = 1; + break; + default: + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::ValueNoLike); + m_sErrorMessage = m_sErrorMessage.replaceAt(m_sErrorMessage.indexOf("#1"),2,pLiteral->getTokenValue()); + break; + } + } + break; + default: + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::FieldNoLike); + break; + } + return nErg; +} + +OSQLParseNode* OSQLParser::buildNode_Date(const double& fValue, sal_Int32 nType) +{ + OSQLParseNode* pNewNode = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::set_fct_spec)); + pNewNode->append(new OSQLInternalNode("{", SQLNodeType::Punctuation)); + OSQLParseNode* pDateNode = new OSQLInternalNode("", SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::odbc_fct_spec)); + pNewNode->append(pDateNode); + pNewNode->append(new OSQLInternalNode("}", SQLNodeType::Punctuation)); + + switch (nType) + { + case DataType::DATE: + { + Date aDate = DBTypeConversion::toDate(fValue,DBTypeConversion::getNULLDate(m_xFormatter->getNumberFormatsSupplier())); + OUString aString = DBTypeConversion::toDateString(aDate); + pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_D)); + pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String)); + break; + } + case DataType::TIME: + { + css::util::Time aTime = DBTypeConversion::toTime(fValue); + OUString aString = DBTypeConversion::toTimeString(aTime); + pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_T)); + pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String)); + break; + } + case DataType::TIMESTAMP: + { + DateTime aDateTime = DBTypeConversion::toDateTime(fValue,DBTypeConversion::getNULLDate(m_xFormatter->getNumberFormatsSupplier())); + if (aDateTime.Seconds || aDateTime.Minutes || aDateTime.Hours) + { + OUString aString = DBTypeConversion::toDateTimeString(aDateTime); + pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_TS)); + pDateNode->append(new OSQLInternalNode(aString, SQLNodeType::String)); + } + else + { + Date aDate(aDateTime.Day,aDateTime.Month,aDateTime.Year); + pDateNode->append(new OSQLInternalNode("", SQLNodeType::Keyword, SQL_TOKEN_D)); + pDateNode->append(new OSQLInternalNode(DBTypeConversion::toDateString(aDate), SQLNodeType::String)); + } + break; + } + } + + return pNewNode; +} + +OSQLParseNode* OSQLParser::buildNode_STR_NUM(OSQLParseNode*& _pLiteral) +{ + OSQLParseNode* pReturn = nullptr; + if ( _pLiteral ) + { + if (m_nFormatKey) + { + sal_Int16 nScale = 0; + try + { + Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, "Decimals" ); + aValue >>= nScale; + } + catch( Exception& ) + { + } + + pReturn = new OSQLInternalNode(stringToDouble(_pLiteral->getTokenValue(),nScale),SQLNodeType::String); + } + else + pReturn = new OSQLInternalNode(_pLiteral->getTokenValue(),SQLNodeType::String); + + delete _pLiteral; + _pLiteral = nullptr; + } + return pReturn; +} + +OUString OSQLParser::stringToDouble(const OUString& _rValue,sal_Int16 _nScale) +{ + OUString aValue; + if(!m_xCharClass.is()) + m_xCharClass = CharacterClassification::create( m_xContext ); + if( s_xLocaleData.is() ) + { + try + { + ParseResult aResult = m_xCharClass->parsePredefinedToken(KParseType::ANY_NUMBER,_rValue,0,m_pData->aLocale,0,OUString(),KParseType::ANY_NUMBER,OUString()); + if((aResult.TokenType & KParseType::IDENTNAME) && aResult.EndPos == _rValue.getLength()) + { + aValue = OUString::number(aResult.Value); + sal_Int32 nPos = aValue.lastIndexOf('.'); + if((nPos+_nScale) < aValue.getLength()) + aValue = aValue.replaceAt(nPos+_nScale,aValue.getLength()-nPos-_nScale,OUString()); + aValue = aValue.replaceAt(aValue.lastIndexOf('.'),1,s_xLocaleData->getLocaleItem(m_pData->aLocale).decimalSeparator); + return aValue; + } + } + catch(Exception&) + { + } + } + return aValue; +} + + +::osl::Mutex& OSQLParser::getMutex() +{ + static ::osl::Mutex aMutex; + return aMutex; +} + + +std::unique_ptr<OSQLParseNode> OSQLParser::predicateTree(OUString& rErrorMessage, const OUString& rStatement, + const Reference< css::util::XNumberFormatter > & xFormatter, + const Reference< XPropertySet > & xField, + bool bUseRealName) +{ + // Guard the parsing + ::osl::MutexGuard aGuard(getMutex()); + // must be reset + setParser(this); + + + // reset the parser + m_xField = xField; + m_xFormatter = xFormatter; + + if (m_xField.is()) + { + sal_Int32 nType=0; + try + { + // get the field name + OUString aString; + + // retrieve the fields name + // #75243# use the RealName of the column if there is any otherwise the name which could be the alias + // of the field + Reference< XPropertySetInfo> xInfo = m_xField->getPropertySetInfo(); + if ( bUseRealName && xInfo->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME))) + m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME)) >>= aString; + else + m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aString; + + m_sFieldName = aString; + + // get the field format key + if ( xInfo->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY))) + m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FORMATKEY)) >>= m_nFormatKey; + else + m_nFormatKey = 0; + + // get the field type + m_xField->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType; + } + catch ( Exception& ) + { + OSL_ASSERT(false); + } + + if (m_nFormatKey && m_xFormatter.is()) + { + Any aValue = getNumberFormatProperty( m_xFormatter, m_nFormatKey, OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_LOCALE) ); + OSL_ENSURE(aValue.getValueType() == cppu::UnoType<css::lang::Locale>::get(), "OSQLParser::PredicateTree : invalid language property !"); + + if (aValue.getValueType() == cppu::UnoType<css::lang::Locale>::get()) + aValue >>= m_pData->aLocale; + } + else + m_pData->aLocale = m_pContext->getPreferredLocale(); + + if ( m_xFormatter.is() ) + { + try + { + Reference< css::util::XNumberFormatsSupplier > xFormatSup = m_xFormatter->getNumberFormatsSupplier(); + if ( xFormatSup.is() ) + { + Reference< css::util::XNumberFormats > xFormats = xFormatSup->getNumberFormats(); + if ( xFormats.is() ) + { + css::lang::Locale aLocale; + aLocale.Language = "en"; + aLocale.Country = "US"; + OUString sFormat("YYYY-MM-DD"); + m_nDateFormatKey = xFormats->queryKey(sFormat,aLocale,false); + if ( m_nDateFormatKey == sal_Int32(-1) ) + m_nDateFormatKey = xFormats->addNew(sFormat, aLocale); + } + } + } + catch ( Exception& ) + { + SAL_WARN( "connectivity.parse","DateFormatKey"); + } + } + + switch (nType) + { + case DataType::DATE: + case DataType::TIME: + case DataType::TIMESTAMP: + s_pScanner->SetRule(OSQLScanner::GetDATERule()); + break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CLOB: + s_pScanner->SetRule(OSQLScanner::GetSTRINGRule()); + break; + default: + if ( s_xLocaleData->getLocaleItem( m_pData->aLocale ).decimalSeparator.toChar() == ',' ) + s_pScanner->SetRule(OSQLScanner::GetGERRule()); + else + s_pScanner->SetRule(OSQLScanner::GetENGRule()); + } + + } + else + s_pScanner->SetRule(OSQLScanner::GetSQLRule()); + + s_pScanner->prepareScan(rStatement, m_pContext, true); + + SQLyylval.pParseNode = nullptr; + // SQLyypvt = NULL; + m_pParseTree = nullptr; + m_sErrorMessage.clear(); + + // Start the parser + if (SQLyyparse() != 0) + { + m_sFieldName.clear(); + m_xField.clear(); + m_xFormatter.clear(); + m_nFormatKey = 0; + m_nDateFormatKey = 0; + + if (m_sErrorMessage.isEmpty()) + m_sErrorMessage = s_pScanner->getErrorMessage(); + if (m_sErrorMessage.isEmpty()) + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::General); + + rErrorMessage = m_sErrorMessage; + + // clear the garbage collector + (*s_pGarbageCollector)->clearAndDelete(); + m_pParseTree.release(); // because the garbage collector deleted it + return nullptr; + } + else + { + (*s_pGarbageCollector)->clear(); + + m_sFieldName.clear(); + m_xField.clear(); + m_xFormatter.clear(); + m_nFormatKey = 0; + m_nDateFormatKey = 0; + + // Return the result (the root parse node): + + // Instead, the parse method sets the member pParseTree and simply returns that + OSL_ENSURE(m_pParseTree != nullptr,"OSQLParser: Parser did not return a ParseTree!"); + return std::move(m_pParseTree); + } +} + + +OSQLParser::OSQLParser(const css::uno::Reference< css::uno::XComponentContext >& rxContext, const IParseContext* _pContext) + :m_pContext(_pContext) + ,m_pData( new OSQLParser_Data ) + ,m_nFormatKey(0) + ,m_nDateFormatKey(0) + ,m_xContext(rxContext) +{ + + + setParser(this); + +#ifdef SQLYYDEBUG +#ifdef SQLYYDEBUG_ON + SQLyydebug = 1; +#endif +#endif + + ::osl::MutexGuard aGuard(getMutex()); + // Do we have to initialize the data? + if (s_nRefCount == 0) + { + s_pScanner = new OSQLScanner(); + s_pScanner->setScanner(); + s_pGarbageCollector = new OSQLParseNodesGarbageCollector(); + + if(!s_xLocaleData.is()) + s_xLocaleData = LocaleData::create(m_xContext); + + // reset to UNKNOWN_RULE + static_assert(OSQLParseNode::UNKNOWN_RULE==0, "UNKNOWN_RULE must be 0 for memset to 0 to work"); + memset(OSQLParser::s_nRuleIDs,0,sizeof(OSQLParser::s_nRuleIDs)); + + const struct + { + OSQLParseNode::Rule eRule; // the parse node's ID for the rule + OString sRuleName; // the name of the rule ("select_statement") + } aRuleDescriptions[] = + { + { OSQLParseNode::select_statement, "select_statement" }, + { OSQLParseNode::table_exp, "table_exp" }, + { OSQLParseNode::table_ref_commalist, "table_ref_commalist" }, + { OSQLParseNode::table_ref, "table_ref" }, + { OSQLParseNode::catalog_name, "catalog_name" }, + { OSQLParseNode::schema_name, "schema_name" }, + { OSQLParseNode::table_name, "table_name" }, + { OSQLParseNode::opt_column_commalist, "opt_column_commalist" }, + { OSQLParseNode::column_commalist, "column_commalist" }, + { OSQLParseNode::column_ref_commalist, "column_ref_commalist" }, + { OSQLParseNode::column_ref, "column_ref" }, + { OSQLParseNode::opt_order_by_clause, "opt_order_by_clause" }, + { OSQLParseNode::ordering_spec_commalist, "ordering_spec_commalist" }, + { OSQLParseNode::ordering_spec, "ordering_spec" }, + { OSQLParseNode::opt_asc_desc, "opt_asc_desc" }, + { OSQLParseNode::where_clause, "where_clause" }, + { OSQLParseNode::opt_where_clause, "opt_where_clause" }, + { OSQLParseNode::search_condition, "search_condition" }, + { OSQLParseNode::comparison, "comparison" }, + { OSQLParseNode::comparison_predicate, "comparison_predicate" }, + { OSQLParseNode::between_predicate, "between_predicate" }, + { OSQLParseNode::like_predicate, "like_predicate" }, + { OSQLParseNode::opt_escape, "opt_escape" }, + { OSQLParseNode::test_for_null, "test_for_null" }, + { OSQLParseNode::scalar_exp_commalist, "scalar_exp_commalist" }, + { OSQLParseNode::scalar_exp, "scalar_exp" }, + { OSQLParseNode::parameter_ref, "parameter_ref" }, + { OSQLParseNode::parameter, "parameter" }, + { OSQLParseNode::general_set_fct, "general_set_fct" }, + { OSQLParseNode::range_variable, "range_variable" }, + { OSQLParseNode::column, "column" }, + { OSQLParseNode::delete_statement_positioned, "delete_statement_positioned" }, + { OSQLParseNode::delete_statement_searched, "delete_statement_searched" }, + { OSQLParseNode::update_statement_positioned, "update_statement_positioned" }, + { OSQLParseNode::update_statement_searched, "update_statement_searched" }, + { OSQLParseNode::assignment_commalist, "assignment_commalist" }, + { OSQLParseNode::assignment, "assignment" }, + { OSQLParseNode::values_or_query_spec, "values_or_query_spec" }, + { OSQLParseNode::insert_statement, "insert_statement" }, + { OSQLParseNode::insert_atom_commalist, "insert_atom_commalist" }, + { OSQLParseNode::insert_atom, "insert_atom" }, + { OSQLParseNode::from_clause, "from_clause" }, + { OSQLParseNode::qualified_join, "qualified_join" }, + { OSQLParseNode::cross_union, "cross_union" }, + { OSQLParseNode::select_sublist, "select_sublist" }, + { OSQLParseNode::derived_column, "derived_column" }, + { OSQLParseNode::column_val, "column_val" }, + { OSQLParseNode::set_fct_spec, "set_fct_spec" }, + { OSQLParseNode::boolean_term, "boolean_term" }, + { OSQLParseNode::boolean_primary, "boolean_primary" }, + { OSQLParseNode::num_value_exp, "num_value_exp" }, + { OSQLParseNode::join_type, "join_type" }, + { OSQLParseNode::position_exp, "position_exp" }, + { OSQLParseNode::extract_exp, "extract_exp" }, + { OSQLParseNode::length_exp, "length_exp" }, + { OSQLParseNode::char_value_fct, "char_value_fct" }, + { OSQLParseNode::odbc_call_spec, "odbc_call_spec" }, + { OSQLParseNode::in_predicate, "in_predicate" }, + { OSQLParseNode::existence_test, "existence_test" }, + { OSQLParseNode::unique_test, "unique_test" }, + { OSQLParseNode::all_or_any_predicate, "all_or_any_predicate" }, + { OSQLParseNode::named_columns_join, "named_columns_join" }, + { OSQLParseNode::join_condition, "join_condition" }, + { OSQLParseNode::joined_table, "joined_table" }, + { OSQLParseNode::boolean_factor, "boolean_factor" }, + { OSQLParseNode::sql_not, "sql_not" }, + { OSQLParseNode::manipulative_statement, "manipulative_statement" }, + { OSQLParseNode::subquery, "subquery" }, + { OSQLParseNode::value_exp_commalist, "value_exp_commalist" }, + { OSQLParseNode::odbc_fct_spec, "odbc_fct_spec" }, + { OSQLParseNode::union_statement, "union_statement" }, + { OSQLParseNode::outer_join_type, "outer_join_type" }, + { OSQLParseNode::char_value_exp, "char_value_exp" }, + { OSQLParseNode::term, "term" }, + { OSQLParseNode::value_exp_primary, "value_exp_primary" }, + { OSQLParseNode::value_exp, "value_exp" }, + { OSQLParseNode::selection, "selection" }, + { OSQLParseNode::fold, "fold" }, + { OSQLParseNode::char_substring_fct, "char_substring_fct" }, + { OSQLParseNode::factor, "factor" }, + { OSQLParseNode::base_table_def, "base_table_def" }, + { OSQLParseNode::base_table_element_commalist, "base_table_element_commalist" }, + { OSQLParseNode::data_type, "data_type" }, + { OSQLParseNode::column_def, "column_def" }, + { OSQLParseNode::table_node, "table_node" }, + { OSQLParseNode::as_clause, "as_clause" }, + { OSQLParseNode::opt_as, "opt_as" }, + { OSQLParseNode::op_column_commalist, "op_column_commalist" }, + { OSQLParseNode::table_primary_as_range_column, "table_primary_as_range_column" }, + { OSQLParseNode::datetime_primary, "datetime_primary" }, + { OSQLParseNode::concatenation, "concatenation" }, + { OSQLParseNode::char_factor, "char_factor" }, + { OSQLParseNode::bit_value_fct, "bit_value_fct" }, + { OSQLParseNode::comparison_predicate_part_2, "comparison_predicate_part_2" }, + { OSQLParseNode::parenthesized_boolean_value_expression, "parenthesized_boolean_value_expression" }, + { OSQLParseNode::character_string_type, "character_string_type" }, + { OSQLParseNode::other_like_predicate_part_2, "other_like_predicate_part_2" }, + { OSQLParseNode::between_predicate_part_2, "between_predicate_part_2" }, + { OSQLParseNode::null_predicate_part_2, "null_predicate_part_2" }, + { OSQLParseNode::cast_spec, "cast_spec" }, + { OSQLParseNode::window_function, "window_function" } + }; + const size_t nRuleMapCount = SAL_N_ELEMENTS( aRuleDescriptions ); + // added a new rule? Adjust this map! + // +1 for UNKNOWN_RULE + static_assert(nRuleMapCount + 1 == static_cast<size_t>(OSQLParseNode::rule_count), "must be equal"); + + for (const auto & aRuleDescription : aRuleDescriptions) + { + // look up the rule description in the our identifier map + sal_uInt32 nParserRuleID = StrToRuleID( aRuleDescription.sRuleName ); + // map the parser's rule ID to the OSQLParseNode::Rule + s_aReverseRuleIDLookup[ nParserRuleID ] = aRuleDescription.eRule; + // and map the OSQLParseNode::Rule to the parser's rule ID + s_nRuleIDs[ aRuleDescription.eRule ] = nParserRuleID; + } + } + ++s_nRefCount; + + if (m_pContext == nullptr) + // take the default context + m_pContext = &s_aDefaultContext; + + m_pData->aLocale = m_pContext->getPreferredLocale(); +} + + +OSQLParser::~OSQLParser() +{ + ::osl::MutexGuard aGuard(getMutex()); + OSL_ENSURE(s_nRefCount > 0, "OSQLParser::~OSQLParser() : suspicious call : has a refcount of 0 !"); + if (!--s_nRefCount) + { + s_pScanner->setScanner(true); + delete s_pScanner; + s_pScanner = nullptr; + + delete s_pGarbageCollector; + s_pGarbageCollector = nullptr; + // Is only set the first time, so we should delete it only when there are no more instances + s_xLocaleData = nullptr; + + RuleIDMap aEmpty; + s_aReverseRuleIDLookup.swap( aEmpty ); + } + m_pParseTree = nullptr; +} + +void OSQLParseNode::substituteParameterNames(OSQLParseNode const * _pNode) +{ + sal_Int32 nCount = _pNode->count(); + for(sal_Int32 i=0;i < nCount;++i) + { + OSQLParseNode* pChildNode = _pNode->getChild(i); + if(SQL_ISRULE(pChildNode,parameter) && pChildNode->count() > 1) + { + OSQLParseNode* pNewNode = new OSQLParseNode("?" ,SQLNodeType::Punctuation,0); + delete pChildNode->replace(pChildNode->getChild(0),pNewNode); + sal_Int32 nChildCount = pChildNode->count(); + for(sal_Int32 j=1;j < nChildCount;++j) + delete pChildNode->removeAt(1); + } + else + substituteParameterNames(pChildNode); + + } +} + +bool OSQLParser::extractDate(OSQLParseNode const * pLiteral,double& _rfValue) +{ + Reference< XNumberFormatsSupplier > xFormatSup = m_xFormatter->getNumberFormatsSupplier(); + Reference< XNumberFormatTypes > xFormatTypes; + if ( xFormatSup.is() ) + xFormatTypes.set(xFormatSup->getNumberFormats(), css::uno::UNO_QUERY); + + // if there is no format key, yet, make sure we have a feasible one for our locale + try + { + if ( !m_nFormatKey && xFormatTypes.is() ) + m_nFormatKey = ::dbtools::getDefaultNumberFormat( m_xField, xFormatTypes, m_pData->aLocale ); + } + catch( Exception& ) { } + const OUString& sValue = pLiteral->getTokenValue(); + sal_Int32 nTryFormat = m_nFormatKey; + bool bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue ); + + // If our format key didn't do, try the default date format for our locale. + if ( !bSuccess && xFormatTypes.is() ) + { + try + { + nTryFormat = xFormatTypes->getStandardFormat( NumberFormat::DATE, m_pData->aLocale ); + } + catch( Exception& ) { } + bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue ); + } + + // if this also didn't do, try ISO format + if ( !bSuccess && xFormatTypes.is() ) + { + try + { + nTryFormat = xFormatTypes->getFormatIndex( NumberFormatIndex::DATE_DIN_YYYYMMDD, m_pData->aLocale ); + } + catch( Exception& ) { } + bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue ); + } + + // if this also didn't do, try fallback date format (en-US) + if ( !bSuccess ) + { + nTryFormat = m_nDateFormatKey; + bSuccess = lcl_saveConvertToNumber( m_xFormatter, nTryFormat, sValue, _rfValue ); + } + return bSuccess; +} + +OSQLParseNode* OSQLParser::buildDate(sal_Int32 _nType,OSQLParseNode*& pLiteral) +{ + // try converting the string into a date, according to our format key + double fValue = 0.0; + OSQLParseNode* pFCTNode = nullptr; + + if ( extractDate(pLiteral,fValue) ) + pFCTNode = buildNode_Date( fValue, _nType); + + delete pLiteral; + pLiteral = nullptr; + + if ( !pFCTNode ) + m_sErrorMessage = m_pContext->getErrorMessage(IParseContext::ErrorCode::InvalidDateCompare); + + return pFCTNode; +} + + +OSQLParseNode::OSQLParseNode(const char * pNewValue, + SQLNodeType eNewNodeType, + sal_uInt32 nNewNodeID) + :m_pParent(nullptr) + ,m_aNodeValue(pNewValue,strlen(pNewValue),RTL_TEXTENCODING_UTF8) + ,m_eNodeType(eNewNodeType) + ,m_nNodeID(nNewNodeID) +{ + OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType"); +} + +OSQLParseNode::OSQLParseNode(const OString &_rNewValue, + SQLNodeType eNewNodeType, + sal_uInt32 nNewNodeID) + :m_pParent(nullptr) + ,m_aNodeValue(OStringToOUString(_rNewValue,RTL_TEXTENCODING_UTF8)) + ,m_eNodeType(eNewNodeType) + ,m_nNodeID(nNewNodeID) +{ + OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType"); +} + +OSQLParseNode::OSQLParseNode(const OUString &_rNewValue, + SQLNodeType eNewNodeType, + sal_uInt32 nNewNodeID) + :m_pParent(nullptr) + ,m_aNodeValue(_rNewValue) + ,m_eNodeType(eNewNodeType) + ,m_nNodeID(nNewNodeID) +{ + OSL_ENSURE(m_eNodeType >= SQLNodeType::Rule && m_eNodeType <= SQLNodeType::Concat,"OSQLParseNode: created with invalid NodeType"); +} + +OSQLParseNode::OSQLParseNode(const OSQLParseNode& rParseNode) +{ + // Set the getParent to NULL + m_pParent = nullptr; + + // Copy the members + m_aNodeValue = rParseNode.m_aNodeValue; + m_eNodeType = rParseNode.m_eNodeType; + m_nNodeID = rParseNode.m_nNodeID; + + + // Remember that we derived from Container. According to SV-Help the Container's + // copy ctor creates a new Container with the same pointers for content. + // This means after copying the Container, for all non-NULL pointers a copy is + // created and reattached instead of the old pointer. + + // If not a leaf, then process SubTrees + for (auto const& child : rParseNode.m_aChildren) + append(new OSQLParseNode(*child)); +} + + +OSQLParseNode& OSQLParseNode::operator=(const OSQLParseNode& rParseNode) +{ + if (this != &rParseNode) + { + // Copy the members - pParent remains the same + m_aNodeValue = rParseNode.m_aNodeValue; + m_eNodeType = rParseNode.m_eNodeType; + m_nNodeID = rParseNode.m_nNodeID; + + m_aChildren.clear(); + + for (auto const& child : rParseNode.m_aChildren) + append(new OSQLParseNode(*child)); + } + return *this; +} + + +bool OSQLParseNode::operator==(OSQLParseNode const & rParseNode) const +{ + // The members must be equal + bool bResult = (m_nNodeID == rParseNode.m_nNodeID) && + (m_eNodeType == rParseNode.m_eNodeType) && + (m_aNodeValue == rParseNode.m_aNodeValue) && + count() == rParseNode.count(); + + // Parameters are not equal! + bResult = bResult && !SQL_ISRULE(this, parameter); + + // compare children + for (size_t i=0; bResult && i < count(); i++) + bResult = *getChild(i) == *rParseNode.getChild(i); + + return bResult; +} + + +OSQLParseNode::~OSQLParseNode() +{ +} + + +void OSQLParseNode::append(OSQLParseNode* pNewNode) +{ + OSL_ENSURE(pNewNode != nullptr, "OSQLParseNode: invalid NewSubTree"); + OSL_ENSURE(pNewNode->getParent() == nullptr, "OSQLParseNode: Node is not an orphan"); + OSL_ENSURE(std::none_of(m_aChildren.begin(), m_aChildren.end(), + [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewNode; }), + "OSQLParseNode::append() Node already element of parent"); + + // Create connection to getParent + pNewNode->setParent( this ); + // and attach the SubTree at the end + m_aChildren.emplace_back(pNewNode); +} + +bool OSQLParseNode::addDateValue(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const +{ + // special display for date/time values + if (SQL_ISRULE(this,set_fct_spec) && SQL_ISPUNCTUATION(m_aChildren[0],"{")) + { + const OSQLParseNode* pODBCNode = m_aChildren[1].get(); + const OSQLParseNode* pODBCNodeChild = pODBCNode->m_aChildren[0].get(); + + if (pODBCNodeChild->getNodeType() == SQLNodeType::Keyword && ( + SQL_ISTOKEN(pODBCNodeChild, D) || + SQL_ISTOKEN(pODBCNodeChild, T) || + SQL_ISTOKEN(pODBCNodeChild, TS) )) + { + OUString suQuote("'"); + if (rParam.bPredicate) + { + if (rParam.aMetaData.shouldEscapeDateTime()) + { + suQuote = "#"; + } + } + else + { + if (rParam.aMetaData.shouldEscapeDateTime()) + { + // suQuote = "'"; + return false; + } + } + + if (!rString.isEmpty()) + rString.append(" "); + rString.append(suQuote); + const OUString sTokenValue = pODBCNode->m_aChildren[1]->getTokenValue(); + if (SQL_ISTOKEN(pODBCNodeChild, D)) + { + rString.append(rParam.bPredicate ? convertDateString(rParam, sTokenValue) : sTokenValue); + } + else if (SQL_ISTOKEN(pODBCNodeChild, T)) + { + rString.append(rParam.bPredicate ? convertTimeString(rParam, sTokenValue) : sTokenValue); + } + else + { + rString.append(rParam.bPredicate ? convertDateTimeString(rParam, sTokenValue) : sTokenValue); + } + rString.append(suQuote); + return true; + } + } + return false; +} + +void OSQLParseNode::replaceNodeValue(const OUString& rTableAlias, const OUString& rColumnName) +{ + for (size_t i=0;i<count();++i) + { + if (SQL_ISRULE(this,column_ref) && count() == 1 && getChild(0)->getTokenValue() == rColumnName) + { + OSQLParseNode * pCol = removeAt(sal_uInt32(0)); + append(new OSQLParseNode(rTableAlias,SQLNodeType::Name)); + append(new OSQLParseNode(".",SQLNodeType::Punctuation)); + append(pCol); + } + else + getChild(i)->replaceNodeValue(rTableAlias,rColumnName); + } +} + +OSQLParseNode* OSQLParseNode::getByRule(OSQLParseNode::Rule eRule) const +{ + OSQLParseNode* pRetNode = nullptr; + if (isRule() && OSQLParser::RuleID(eRule) == getRuleID()) + pRetNode = const_cast<OSQLParseNode*>(this); + else + { + for (auto const& child : m_aChildren) + { + pRetNode = child->getByRule(eRule); + if (pRetNode) + break; + } + } + return pRetNode; +} + +static OSQLParseNode* MakeANDNode(OSQLParseNode *pLeftLeaf,OSQLParseNode *pRightLeaf) +{ + OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_term)); + pNewNode->append(pLeftLeaf); + pNewNode->append(new OSQLParseNode("AND",SQLNodeType::Keyword,SQL_TOKEN_AND)); + pNewNode->append(pRightLeaf); + return pNewNode; +} + +static OSQLParseNode* MakeORNode(OSQLParseNode *pLeftLeaf,OSQLParseNode *pRightLeaf) +{ + OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::search_condition)); + pNewNode->append(pLeftLeaf); + pNewNode->append(new OSQLParseNode("OR",SQLNodeType::Keyword,SQL_TOKEN_OR)); + pNewNode->append(pRightLeaf); + return pNewNode; +} + +void OSQLParseNode::disjunctiveNormalForm(OSQLParseNode*& pSearchCondition) +{ + if(!pSearchCondition) // no where condition at entry point + return; + + OSQLParseNode::absorptions(pSearchCondition); + // '(' search_condition ')' + if (SQL_ISRULE(pSearchCondition,boolean_primary)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(1); + disjunctiveNormalForm(pLeft); + } + // search_condition SQL_TOKEN_OR boolean_term + else if (SQL_ISRULE(pSearchCondition,search_condition)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0); + disjunctiveNormalForm(pLeft); + + OSQLParseNode* pRight = pSearchCondition->getChild(2); + disjunctiveNormalForm(pRight); + } + // boolean_term SQL_TOKEN_AND boolean_factor + else if (SQL_ISRULE(pSearchCondition,boolean_term)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0); + disjunctiveNormalForm(pLeft); + + OSQLParseNode* pRight = pSearchCondition->getChild(2); + disjunctiveNormalForm(pRight); + + OSQLParseNode* pNewNode = nullptr; + // '(' search_condition ')' on left side + if(pLeft->count() == 3 && SQL_ISRULE(pLeft,boolean_primary) && SQL_ISRULE(pLeft->getChild(1),search_condition)) + { + // and-or tree on left side + OSQLParseNode* pOr = pLeft->getChild(1); + OSQLParseNode* pNewLeft = nullptr; + OSQLParseNode* pNewRight = nullptr; + + // cut right from parent + pSearchCondition->removeAt(2); + + pNewRight = MakeANDNode(pOr->removeAt(2) ,pRight); + pNewLeft = MakeANDNode(pOr->removeAt(sal_uInt32(0)) ,new OSQLParseNode(*pRight)); + pNewNode = MakeORNode(pNewLeft,pNewRight); + // and append new Node + replaceAndReset(pSearchCondition,pNewNode); + + disjunctiveNormalForm(pSearchCondition); + } + else if(pRight->count() == 3 && SQL_ISRULE(pRight,boolean_primary) && SQL_ISRULE(pRight->getChild(1),search_condition)) + { // '(' search_condition ')' on right side + // and-or tree on right side + // a and (b or c) + OSQLParseNode* pOr = pRight->getChild(1); + OSQLParseNode* pNewLeft = nullptr; + OSQLParseNode* pNewRight = nullptr; + + // cut left from parent + pSearchCondition->removeAt(sal_uInt32(0)); + + pNewRight = MakeANDNode(pLeft,pOr->removeAt(2)); + pNewLeft = MakeANDNode(new OSQLParseNode(*pLeft),pOr->removeAt(sal_uInt32(0))); + pNewNode = MakeORNode(pNewLeft,pNewRight); + + // and append new Node + replaceAndReset(pSearchCondition,pNewNode); + disjunctiveNormalForm(pSearchCondition); + } + else if(SQL_ISRULE(pLeft,boolean_primary) && (!SQL_ISRULE(pLeft->getChild(1),search_condition) || !SQL_ISRULE(pLeft->getChild(1),boolean_term))) + pSearchCondition->replace(pLeft, pLeft->removeAt(1)); + else if(SQL_ISRULE(pRight,boolean_primary) && (!SQL_ISRULE(pRight->getChild(1),search_condition) || !SQL_ISRULE(pRight->getChild(1),boolean_term))) + pSearchCondition->replace(pRight, pRight->removeAt(1)); + } +} + +void OSQLParseNode::negateSearchCondition(OSQLParseNode*& pSearchCondition, bool bNegate) +{ + if(!pSearchCondition) // no where condition at entry point + return; + // '(' search_condition ')' + if (pSearchCondition->count() == 3 && SQL_ISRULE(pSearchCondition,boolean_primary)) + { + OSQLParseNode* pRight = pSearchCondition->getChild(1); + negateSearchCondition(pRight,bNegate); + } + // search_condition SQL_TOKEN_OR boolean_term + else if (SQL_ISRULE(pSearchCondition,search_condition)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0); + OSQLParseNode* pRight = pSearchCondition->getChild(2); + if(bNegate) + { + OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_term)); + pNewNode->append(pSearchCondition->removeAt(sal_uInt32(0))); + pNewNode->append(new OSQLParseNode("AND",SQLNodeType::Keyword,SQL_TOKEN_AND)); + pNewNode->append(pSearchCondition->removeAt(sal_uInt32(1))); + replaceAndReset(pSearchCondition,pNewNode); + + pLeft = pNewNode->getChild(0); + pRight = pNewNode->getChild(2); + } + + negateSearchCondition(pLeft,bNegate); + negateSearchCondition(pRight,bNegate); + } + // boolean_term SQL_TOKEN_AND boolean_factor + else if (SQL_ISRULE(pSearchCondition,boolean_term)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0); + OSQLParseNode* pRight = pSearchCondition->getChild(2); + if(bNegate) + { + OSQLParseNode* pNewNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::search_condition)); + pNewNode->append(pSearchCondition->removeAt(sal_uInt32(0))); + pNewNode->append(new OSQLParseNode("OR",SQLNodeType::Keyword,SQL_TOKEN_OR)); + pNewNode->append(pSearchCondition->removeAt(sal_uInt32(1))); + replaceAndReset(pSearchCondition,pNewNode); + + pLeft = pNewNode->getChild(0); + pRight = pNewNode->getChild(2); + } + + negateSearchCondition(pLeft,bNegate); + negateSearchCondition(pRight,bNegate); + } + // SQL_TOKEN_NOT ( boolean_primary ) + else if (SQL_ISRULE(pSearchCondition,boolean_factor)) + { + OSQLParseNode *pNot = pSearchCondition->removeAt(sal_uInt32(0)); + delete pNot; + OSQLParseNode *pBooleanTest = pSearchCondition->removeAt(sal_uInt32(0)); + // TODO is this needed // pBooleanTest->setParent(NULL); + replaceAndReset(pSearchCondition,pBooleanTest); + + if (!bNegate) + negateSearchCondition(pSearchCondition, true); // negate all deeper values + } + // row_value_constructor comparison row_value_constructor + // row_value_constructor comparison any_all_some subquery + else if(bNegate && (SQL_ISRULE(pSearchCondition,comparison_predicate) || SQL_ISRULE(pSearchCondition,all_or_any_predicate))) + { + assert(pSearchCondition->count() == 3); + OSQLParseNode* pComparison = pSearchCondition->getChild(1); + if(SQL_ISRULE(pComparison, comparison)) + { + assert(pComparison->count() == 2 || + pComparison->count() == 4); + assert(SQL_ISTOKEN(pComparison->getChild(0), IS)); + + OSQLParseNode* pNot = pComparison->getChild(1); + OSQLParseNode* pNotNot = nullptr; + if(pNot->isRule()) // no NOT token (empty rule) + pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT); + else + { + assert(SQL_ISTOKEN(pNot,NOT)); + pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not)); + } + pComparison->replace(pNot, pNotNot); + delete pNot; + } + else + { + OSQLParseNode* pNewComparison; + switch(pComparison->getNodeType()) + { + default: + case SQLNodeType::Equal: + assert(pComparison->getNodeType() == SQLNodeType::Equal && + "OSQLParseNode::negateSearchCondition: unexpected node type!"); + pNewComparison = new OSQLParseNode("<>",SQLNodeType::NotEqual,SQL_NOTEQUAL); + break; + case SQLNodeType::Less: + pNewComparison = new OSQLParseNode(">=",SQLNodeType::GreatEq,SQL_GREATEQ); + break; + case SQLNodeType::Great: + pNewComparison = new OSQLParseNode("<=",SQLNodeType::LessEq,SQL_LESSEQ); + break; + case SQLNodeType::LessEq: + pNewComparison = new OSQLParseNode(">",SQLNodeType::Great,SQL_GREAT); + break; + case SQLNodeType::GreatEq: + pNewComparison = new OSQLParseNode("<",SQLNodeType::Less,SQL_LESS); + break; + case SQLNodeType::NotEqual: + pNewComparison = new OSQLParseNode("=",SQLNodeType::Equal,SQL_EQUAL); + break; + } + pSearchCondition->replace(pComparison, pNewComparison); + delete pComparison; + } + } + + else if(bNegate && (SQL_ISRULE(pSearchCondition,test_for_null) || + SQL_ISRULE(pSearchCondition,in_predicate) || + SQL_ISRULE(pSearchCondition,between_predicate) )) + { + OSQLParseNode* pPart2 = pSearchCondition->getChild(1); + sal_uInt32 nNotPos = 0; + if ( SQL_ISRULE( pSearchCondition, test_for_null ) ) + nNotPos = 1; + + OSQLParseNode* pNot = pPart2->getChild(nNotPos); + OSQLParseNode* pNotNot = nullptr; + if(pNot->isRule()) // no NOT token (empty rule) + pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT); + else + { + assert(SQL_ISTOKEN(pNot,NOT)); + pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not)); + } + pPart2->replace(pNot, pNotNot); + delete pNot; + } + else if(bNegate && SQL_ISRULE(pSearchCondition,like_predicate)) + { + OSQLParseNode* pNot = pSearchCondition->getChild( 1 )->getChild( 0 ); + OSQLParseNode* pNotNot = nullptr; + if(pNot->isRule()) + pNotNot = new OSQLParseNode("NOT",SQLNodeType::Keyword,SQL_TOKEN_NOT); + else + pNotNot = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::sql_not)); + pSearchCondition->getChild( 1 )->replace(pNot, pNotNot); + delete pNot; + } +} + +void OSQLParseNode::eraseBraces(OSQLParseNode*& pSearchCondition) +{ + if (!(pSearchCondition && (SQL_ISRULE(pSearchCondition,boolean_primary) || (pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") && + SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")"))))) + return; + + OSQLParseNode* pRight = pSearchCondition->getChild(1); + absorptions(pRight); + // if child is not an or and tree then delete () around child + if(!(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || SQL_ISRULE(pSearchCondition->getChild(1),search_condition)) || + SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || // and can always stand without () + (SQL_ISRULE(pSearchCondition->getChild(1),search_condition) && SQL_ISRULE(pSearchCondition->getParent(),search_condition))) + { + OSQLParseNode* pNode = pSearchCondition->removeAt(1); + replaceAndReset(pSearchCondition,pNode); + } +} + +void OSQLParseNode::absorptions(OSQLParseNode*& pSearchCondition) +{ + if(!pSearchCondition) // no where condition at entry point + return; + + eraseBraces(pSearchCondition); + + if(SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0); + absorptions(pLeft); + OSQLParseNode* pRight = pSearchCondition->getChild(2); + absorptions(pRight); + } + + sal_uInt32 nPos = 0; + // a and a || a or a + OSQLParseNode* pNewNode = nullptr; + if(( SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition)) + && *pSearchCondition->getChild(0) == *pSearchCondition->getChild(2)) + { + pNewNode = pSearchCondition->removeAt(sal_uInt32(0)); + replaceAndReset(pSearchCondition,pNewNode); + } + // ( a or b ) and a || ( b or c ) and a + // a and ( a or b ) || a and ( b or c ) + else if ( SQL_ISRULE(pSearchCondition,boolean_term) + && ( + ( SQL_ISRULE(pSearchCondition->getChild(nPos = 0),boolean_primary) + || SQL_ISRULE(pSearchCondition->getChild(nPos),search_condition) + ) + || ( SQL_ISRULE(pSearchCondition->getChild(nPos = 2),boolean_primary) + || SQL_ISRULE(pSearchCondition->getChild(nPos),search_condition) + ) + ) + ) + { + OSQLParseNode* p2ndSearch = pSearchCondition->getChild(nPos); + if ( SQL_ISRULE(p2ndSearch,boolean_primary) ) + p2ndSearch = p2ndSearch->getChild(1); + + if ( *p2ndSearch->getChild(0) == *pSearchCondition->getChild(2-nPos) ) // a and ( a or b) -> a or b + { + pNewNode = pSearchCondition->removeAt(sal_uInt32(0)); + replaceAndReset(pSearchCondition,pNewNode); + + } + else if ( *p2ndSearch->getChild(2) == *pSearchCondition->getChild(2-nPos) ) // a and ( b or a) -> a or b + { + pNewNode = pSearchCondition->removeAt(sal_uInt32(2)); + replaceAndReset(pSearchCondition,pNewNode); + } + else if ( p2ndSearch->getByRule(OSQLParseNode::search_condition) ) + { + // a and ( b or c ) -> ( a and b ) or ( a and c ) + // ( b or c ) and a -> ( a and b ) or ( a and c ) + OSQLParseNode* pC = p2ndSearch->removeAt(sal_uInt32(2)); + OSQLParseNode* pB = p2ndSearch->removeAt(sal_uInt32(0)); + OSQLParseNode* pA = pSearchCondition->removeAt(sal_uInt32(2)-nPos); + + OSQLParseNode* p1stAnd = MakeANDNode(pA,pB); + OSQLParseNode* p2ndAnd = MakeANDNode(new OSQLParseNode(*pA),pC); + pNewNode = MakeORNode(p1stAnd,p2ndAnd); + OSQLParseNode* pNode = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary)); + pNode->append(new OSQLParseNode("(",SQLNodeType::Punctuation)); + pNode->append(pNewNode); + pNode->append(new OSQLParseNode(")",SQLNodeType::Punctuation)); + OSQLParseNode::eraseBraces(p1stAnd); + OSQLParseNode::eraseBraces(p2ndAnd); + replaceAndReset(pSearchCondition,pNode); + } + } + // a or a and b || a or b and a + else if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(2),boolean_term)) + { + if(*pSearchCondition->getChild(2)->getChild(0) == *pSearchCondition->getChild(0)) + { + pNewNode = pSearchCondition->removeAt(sal_uInt32(0)); + replaceAndReset(pSearchCondition,pNewNode); + } + else if(*pSearchCondition->getChild(2)->getChild(2) == *pSearchCondition->getChild(0)) + { + pNewNode = pSearchCondition->removeAt(sal_uInt32(0)); + replaceAndReset(pSearchCondition,pNewNode); + } + } + // a and b or a || b and a or a + else if(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(0),boolean_term)) + { + if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)) + { + pNewNode = pSearchCondition->removeAt(sal_uInt32(2)); + replaceAndReset(pSearchCondition,pNewNode); + } + else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)) + { + pNewNode = pSearchCondition->removeAt(sal_uInt32(2)); + replaceAndReset(pSearchCondition,pNewNode); + } + } + eraseBraces(pSearchCondition); +} + +void OSQLParseNode::compress(OSQLParseNode *&pSearchCondition) +{ + if(!pSearchCondition) // no WHERE condition at entry point + return; + + OSQLParseNode::eraseBraces(pSearchCondition); + + if(SQL_ISRULE(pSearchCondition,boolean_term) || SQL_ISRULE(pSearchCondition,search_condition)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0); + compress(pLeft); + + OSQLParseNode* pRight = pSearchCondition->getChild(2); + compress(pRight); + } + else if( SQL_ISRULE(pSearchCondition,boolean_primary) || (pSearchCondition->count() == 3 && SQL_ISPUNCTUATION(pSearchCondition->getChild(0),"(") && + SQL_ISPUNCTUATION(pSearchCondition->getChild(2),")"))) + { + OSQLParseNode* pRight = pSearchCondition->getChild(1); + compress(pRight); + // if child is not an or and tree then delete () around child + if(!(SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) || SQL_ISRULE(pSearchCondition->getChild(1),search_condition)) || + (SQL_ISRULE(pSearchCondition->getChild(1),boolean_term) && SQL_ISRULE(pSearchCondition->getParent(),boolean_term)) || + (SQL_ISRULE(pSearchCondition->getChild(1),search_condition) && SQL_ISRULE(pSearchCondition->getParent(),search_condition))) + { + OSQLParseNode* pNode = pSearchCondition->removeAt(1); + replaceAndReset(pSearchCondition,pNode); + } + } + + // or with two and trees where one element of the and trees are equal + if(!(SQL_ISRULE(pSearchCondition,search_condition) && SQL_ISRULE(pSearchCondition->getChild(0),boolean_term) && SQL_ISRULE(pSearchCondition->getChild(2),boolean_term))) + return; + + if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)->getChild(0)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(2); + OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(2); + OSQLParseNode* pNode = MakeORNode(pLeft,pRight); + + OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary)); + pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation)); + pNewRule->append(pNode); + pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation)); + + OSQLParseNode::eraseBraces(pLeft); + OSQLParseNode::eraseBraces(pRight); + + pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)),pNewRule); + replaceAndReset(pSearchCondition,pNode); + } + else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)->getChild(0)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)); + OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(2); + OSQLParseNode* pNode = MakeORNode(pLeft,pRight); + + OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary)); + pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation)); + pNewRule->append(pNode); + pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation)); + + OSQLParseNode::eraseBraces(pLeft); + OSQLParseNode::eraseBraces(pRight); + + pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(1),pNewRule); + replaceAndReset(pSearchCondition,pNode); + } + else if(*pSearchCondition->getChild(0)->getChild(0) == *pSearchCondition->getChild(2)->getChild(2)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(2); + OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(sal_uInt32(0)); + OSQLParseNode* pNode = MakeORNode(pLeft,pRight); + + OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary)); + pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation)); + pNewRule->append(pNode); + pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation)); + + OSQLParseNode::eraseBraces(pLeft); + OSQLParseNode::eraseBraces(pRight); + + pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)),pNewRule); + replaceAndReset(pSearchCondition,pNode); + } + else if(*pSearchCondition->getChild(0)->getChild(2) == *pSearchCondition->getChild(2)->getChild(2)) + { + OSQLParseNode* pLeft = pSearchCondition->getChild(0)->removeAt(sal_uInt32(0)); + OSQLParseNode* pRight = pSearchCondition->getChild(2)->removeAt(sal_uInt32(0)); + OSQLParseNode* pNode = MakeORNode(pLeft,pRight); + + OSQLParseNode* pNewRule = new OSQLParseNode(OUString(),SQLNodeType::Rule,OSQLParser::RuleID(OSQLParseNode::boolean_primary)); + pNewRule->append(new OSQLParseNode("(",SQLNodeType::Punctuation)); + pNewRule->append(pNode); + pNewRule->append(new OSQLParseNode(")",SQLNodeType::Punctuation)); + + OSQLParseNode::eraseBraces(pLeft); + OSQLParseNode::eraseBraces(pRight); + + pNode = MakeANDNode(pSearchCondition->getChild(0)->removeAt(1),pNewRule); + replaceAndReset(pSearchCondition,pNode); + } +} +#if OSL_DEBUG_LEVEL > 1 + +void OSQLParseNode::showParseTree( OUString& rString ) const +{ + OUStringBuffer aBuf; + showParseTree( aBuf, 0 ); + rString = aBuf.makeStringAndClear(); +} + + +void OSQLParseNode::showParseTree( OUStringBuffer& _inout_rBuffer, sal_uInt32 nLevel ) const +{ + for ( sal_uInt32 j=0; j<nLevel; ++j) + _inout_rBuffer.appendAscii( " " ); + + if ( !isToken() ) + { + // Rule name as rule + _inout_rBuffer.appendAscii( "RULE_ID: " ); + _inout_rBuffer.append( (sal_Int32)getRuleID() ); + _inout_rBuffer.append( '(' ); + _inout_rBuffer.append( OSQLParser::RuleIDToStr( getRuleID() ) ); + _inout_rBuffer.append( ')' ); + _inout_rBuffer.append( '\n' ); + + // Get the first sub tree + for (auto const& child : m_aChildren) + child->showParseTree( _inout_rBuffer, nLevel+1 ); + } + else + { + // Found a token + switch (m_eNodeType) + { + + case SQLNodeType::Keyword: + _inout_rBuffer.appendAscii( "SQL_KEYWORD: " ); + _inout_rBuffer.append( OStringToOUString( OSQLParser::TokenIDToStr( getTokenID() ), RTL_TEXTENCODING_UTF8 ) ); + _inout_rBuffer.append( '\n' ); + break; + + case SQLNodeType::Name: + _inout_rBuffer.appendAscii( "SQL_NAME: " ); + _inout_rBuffer.append( '"' ); + _inout_rBuffer.append( m_aNodeValue ); + _inout_rBuffer.append( '"' ); + _inout_rBuffer.append( '\n' ); + break; + + case SQLNodeType::String: + _inout_rBuffer.appendAscii( "SQL_STRING: " ); + _inout_rBuffer.append( '\'' ); + _inout_rBuffer.append( m_aNodeValue ); + _inout_rBuffer.append( '\'' ); + _inout_rBuffer.append( '\n' ); + break; + + case SQLNodeType::IntNum: + _inout_rBuffer.appendAscii( "SQL_INTNUM: " ); + _inout_rBuffer.append( m_aNodeValue ); + _inout_rBuffer.append( '\n' ); + break; + + case SQLNodeType::ApproxNum: + _inout_rBuffer.appendAscii( "SQL_APPROXNUM: " ); + _inout_rBuffer.append( m_aNodeValue ); + _inout_rBuffer.append( '\n' ); + break; + + case SQLNodeType::Punctuation: + _inout_rBuffer.appendAscii( "SQL_PUNCTUATION: " ); + _inout_rBuffer.append( m_aNodeValue ); + _inout_rBuffer.append( '\n' ); + break; + + case SQLNodeType::Equal: + case SQLNodeType::Less: + case SQLNodeType::Great: + case SQLNodeType::LessEq: + case SQLNodeType::GreatEq: + case SQLNodeType::NotEqual: + _inout_rBuffer.append( m_aNodeValue ); + _inout_rBuffer.append( '\n' ); + break; + + case SQLNodeType::AccessDate: + _inout_rBuffer.appendAscii( "SQL_ACCESS_DATE: " ); + _inout_rBuffer.append( m_aNodeValue ); + _inout_rBuffer.append( '\n' ); + break; + + case SQLNodeType::Concat: + _inout_rBuffer.appendAscii( "||" ); + _inout_rBuffer.append( '\n' ); + break; + + default: + SAL_INFO( "connectivity.parse", "-- " << int( m_eNodeType ) ); + SAL_WARN( "connectivity.parse", "OSQLParser::ShowParseTree: unzulaessiger NodeType" ); + } + } +} +#endif // OSL_DEBUG_LEVEL > 0 + +// Insert methods + +void OSQLParseNode::insert(sal_uInt32 nPos, OSQLParseNode* pNewSubTree) +{ + OSL_ENSURE(pNewSubTree != nullptr, "OSQLParseNode: invalid NewSubTree"); + OSL_ENSURE(pNewSubTree->getParent() == nullptr, "OSQLParseNode: Node is not an orphan"); + + // Create connection to getParent + pNewSubTree->setParent( this ); + m_aChildren.emplace(m_aChildren.begin() + nPos, pNewSubTree); +} + +// removeAt methods + +OSQLParseNode* OSQLParseNode::removeAt(sal_uInt32 nPos) +{ + OSL_ENSURE(nPos < m_aChildren.size(),"Illegal position for removeAt"); + auto aPos(m_aChildren.begin() + nPos); + auto pNode = std::move(*aPos); + + // Set the getParent of the removed node to NULL + pNode->setParent( nullptr ); + + m_aChildren.erase(aPos); + return pNode.release(); +} + +// Replace methods + +OSQLParseNode* OSQLParseNode::replace(OSQLParseNode* pOldSubNode, OSQLParseNode* pNewSubNode ) +{ + OSL_ENSURE(pOldSubNode != nullptr && pNewSubNode != nullptr, "OSQLParseNode: invalid nodes"); + OSL_ENSURE(pNewSubNode->getParent() == nullptr, "OSQLParseNode: node already has getParent"); + OSL_ENSURE(std::any_of(m_aChildren.begin(), m_aChildren.end(), + [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pOldSubNode; }), + "OSQLParseNode::Replace() Node not element of parent"); + OSL_ENSURE(std::none_of(m_aChildren.begin(), m_aChildren.end(), + [&] (std::unique_ptr<OSQLParseNode> const & r) { return r.get() == pNewSubNode; }), + "OSQLParseNode::Replace() Node already element of parent"); + + pOldSubNode->setParent( nullptr ); + pNewSubNode->setParent( this ); + auto it = std::find_if(m_aChildren.begin(), m_aChildren.end(), + [&pOldSubNode](const std::unique_ptr<OSQLParseNode>& rxChild) { return rxChild.get() == pOldSubNode; }); + if (it != m_aChildren.end()) + { + it->release(); + it->reset(pNewSubNode); + } + return pOldSubNode; +} + +void OSQLParseNode::parseLeaf(OUStringBuffer& rString, const SQLParseNodeParameter& rParam) const +{ + // Found a leaf + // Append content to the output string + switch (m_eNodeType) + { + case SQLNodeType::Keyword: + { + if (!rString.isEmpty()) + rString.append(" "); + + const OString sT = OSQLParser::TokenIDToStr(m_nNodeID, rParam.bInternational ? &rParam.m_rContext : nullptr); + rString.append(OStringToOUString(sT,RTL_TEXTENCODING_UTF8)); + } break; + case SQLNodeType::String: + if (!rString.isEmpty()) + rString.append(" "); + rString.append(SetQuotation(m_aNodeValue,"\'","\'\'")); + break; + case SQLNodeType::Name: + if (!rString.isEmpty()) + { + switch(rString[rString.getLength()-1]) + { + case ' ' : + case '.' : break; + default : + if ( rParam.aMetaData.getCatalogSeparator().isEmpty() + || rString[rString.getLength() - 1] != rParam.aMetaData.getCatalogSeparator().toChar() + ) + rString.append(" "); + break; + } + } + if (rParam.bQuote) + { + if (rParam.bPredicate) + { + rString.append("["); + rString.append(m_aNodeValue); + rString.append("]"); + } + else + rString.append(SetQuotation(m_aNodeValue, + rParam.aMetaData.getIdentifierQuoteString(), rParam.aMetaData.getIdentifierQuoteString() )); + } + else + rString.append(m_aNodeValue); + break; + case SQLNodeType::AccessDate: + if (!rString.isEmpty()) + rString.append(" "); + rString.append("#"); + rString.append(m_aNodeValue); + rString.append("#"); + break; + + case SQLNodeType::IntNum: + case SQLNodeType::ApproxNum: + { + OUString aTmp = m_aNodeValue; + static OUString strPoint("."); + if (rParam.bInternational && rParam.bPredicate && rParam.sDecSep != strPoint) + aTmp = aTmp.replaceAll(strPoint, rParam.sDecSep); + + if (!rString.isEmpty()) + rString.append(" "); + rString.append(aTmp); + + } break; + case SQLNodeType::Punctuation: + if ( getParent() && SQL_ISRULE(getParent(),cast_spec) && m_aNodeValue.toChar() == '(' ) // no spaces in front of '(' + { + rString.append(m_aNodeValue); + break; + } + [[fallthrough]]; + default: + if (!rString.isEmpty() && m_aNodeValue.toChar() != '.' && m_aNodeValue.toChar() != ':' ) + { + switch( rString[rString.getLength() - 1] ) + { + case ' ' : + case '.' : break; + default : + if ( rParam.aMetaData.getCatalogSeparator().isEmpty() + || rString[rString.getLength() - 1] != rParam.aMetaData.getCatalogSeparator().toChar() + ) + rString.append(" "); + break; + } + } + rString.append(m_aNodeValue); + } +} + + +sal_Int32 OSQLParser::getFunctionReturnType(const OUString& _sFunctionName, const IParseContext* pContext) +{ + sal_Int32 nType = DataType::VARCHAR; + OString sFunctionName(OUStringToOString(_sFunctionName,RTL_TEXTENCODING_UTF8)); + + if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ASCII,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_BIT_LENGTH,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CHAR,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CHAR_LENGTH,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CONCAT,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DIFFERENCE,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_INSERT,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LCASE,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LEFT,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LENGTH,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOCATE,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOCATE_2,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LTRIM,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_OCTET_LENGTH,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_POSITION,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_REPEAT,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_REPLACE,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RIGHT,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RTRIM,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SOUNDEX,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SPACE,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SUBSTRING,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_UCASE,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_DATE,pContext))) nType = DataType::DATE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_TIME,pContext))) nType = DataType::TIME; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURRENT_TIMESTAMP,pContext))) nType = DataType::TIMESTAMP; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURDATE,pContext))) nType = DataType::DATE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DATEDIFF,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DATEVALUE,pContext))) nType = DataType::DATE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CURTIME,pContext))) nType = DataType::TIME; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYNAME,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFMONTH,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFWEEK,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DAYOFYEAR,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_EXTRACT,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_HOUR,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MINUTE,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MONTH,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MONTHNAME,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_NOW,pContext))) nType = DataType::TIMESTAMP; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_QUARTER,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SECOND,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMESTAMPADD,pContext))) nType = DataType::TIMESTAMP; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMESTAMPDIFF,pContext))) nType = DataType::TIMESTAMP; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TIMEVALUE,pContext))) nType = DataType::TIMESTAMP; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_WEEK,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_YEAR,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ABS,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ACOS,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ASIN,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ATAN,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ATAN2,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_CEILING,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COS,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COT,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_DEGREES,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_EXP,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_FLOOR,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOGF,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOG,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOG10,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LN,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MOD,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_PI,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_POWER,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RADIANS,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_RAND,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ROUND,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_ROUNDMAGIC,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SIGN,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SIN,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SQRT,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TAN,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_TRUNCATE,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_COUNT,pContext))) nType = DataType::INTEGER; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MAX,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_MIN,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_AVG,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_SUM,pContext))) nType = DataType::DOUBLE; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_LOWER,pContext))) nType = DataType::VARCHAR; + else if(sFunctionName.equalsIgnoreAsciiCase(TokenIDToStr(SQL_TOKEN_UPPER,pContext))) nType = DataType::VARCHAR; + + return nType; +} + +sal_Int32 OSQLParser::getFunctionParameterType(sal_uInt32 _nTokenId, sal_uInt32 _nPos) +{ + sal_Int32 nType = DataType::VARCHAR; + + if(_nTokenId == SQL_TOKEN_CHAR) nType = DataType::INTEGER; + else if(_nTokenId == SQL_TOKEN_INSERT) + { + if ( _nPos == 2 || _nPos == 3 ) + nType = DataType::INTEGER; + } + else if(_nTokenId == SQL_TOKEN_LEFT) + { + if ( _nPos == 2 ) + nType = DataType::INTEGER; + } + else if(_nTokenId == SQL_TOKEN_LOCATE) + { + if ( _nPos == 3 ) + nType = DataType::INTEGER; + } + else if(_nTokenId == SQL_TOKEN_LOCATE_2) + { + if ( _nPos == 3 ) + nType = DataType::INTEGER; + } + else if( _nTokenId == SQL_TOKEN_REPEAT || _nTokenId == SQL_TOKEN_RIGHT ) + { + if ( _nPos == 2 ) + nType = DataType::INTEGER; + } + else if(_nTokenId == SQL_TOKEN_SPACE ) + { + nType = DataType::INTEGER; + } + else if(_nTokenId == SQL_TOKEN_SUBSTRING) + { + if ( _nPos != 1 ) + nType = DataType::INTEGER; + } + else if(_nTokenId == SQL_TOKEN_DATEDIFF) + { + if ( _nPos != 1 ) + nType = DataType::TIMESTAMP; + } + else if(_nTokenId == SQL_TOKEN_DATEVALUE) + nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_DAYNAME) + nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_DAYOFMONTH) + nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_DAYOFWEEK) + nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_DAYOFYEAR) + nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_EXTRACT) nType = DataType::VARCHAR; + else if(_nTokenId == SQL_TOKEN_HOUR) nType = DataType::TIME; + else if(_nTokenId == SQL_TOKEN_MINUTE) nType = DataType::TIME; + else if(_nTokenId == SQL_TOKEN_MONTH) nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_MONTHNAME) nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_NOW) nType = DataType::TIMESTAMP; + else if(_nTokenId == SQL_TOKEN_QUARTER) nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_SECOND) nType = DataType::TIME; + else if(_nTokenId == SQL_TOKEN_TIMESTAMPADD) nType = DataType::TIMESTAMP; + else if(_nTokenId == SQL_TOKEN_TIMESTAMPDIFF) nType = DataType::TIMESTAMP; + else if(_nTokenId == SQL_TOKEN_TIMEVALUE) nType = DataType::TIMESTAMP; + else if(_nTokenId == SQL_TOKEN_WEEK) nType = DataType::DATE; + else if(_nTokenId == SQL_TOKEN_YEAR) nType = DataType::DATE; + + else if(_nTokenId == SQL_TOKEN_ABS) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_ACOS) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_ASIN) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_ATAN) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_ATAN2) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_CEILING) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_COS) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_COT) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_DEGREES) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_EXP) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_FLOOR) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_LOGF) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_LOG) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_LOG10) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_LN) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_MOD) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_PI) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_POWER) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_RADIANS) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_RAND) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_ROUND) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_ROUNDMAGIC) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_SIGN) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_SIN) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_SQRT) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_TAN) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_TRUNCATE) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_COUNT) nType = DataType::INTEGER; + else if(_nTokenId == SQL_TOKEN_MAX) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_MIN) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_AVG) nType = DataType::DOUBLE; + else if(_nTokenId == SQL_TOKEN_SUM) nType = DataType::DOUBLE; + + else if(_nTokenId == SQL_TOKEN_LOWER) nType = DataType::VARCHAR; + else if(_nTokenId == SQL_TOKEN_UPPER) nType = DataType::VARCHAR; + + return nType; +} + + +const SQLError& OSQLParser::getErrorHelper() const +{ + return m_pData->aErrors; +} + + +OSQLParseNode::Rule OSQLParseNode::getKnownRuleID() const +{ + if ( !isRule() ) + return UNKNOWN_RULE; + return OSQLParser::RuleIDToRule( getRuleID() ); +} + +OUString OSQLParseNode::getTableRange(const OSQLParseNode* _pTableRef) +{ + OSL_ENSURE(_pTableRef && _pTableRef->count() > 1 && _pTableRef->getKnownRuleID() == OSQLParseNode::table_ref,"Invalid node give, only table ref is allowed!"); + const sal_uInt32 nCount = _pTableRef->count(); + OUString sTableRange; + if ( nCount == 2 || (nCount == 3 && !_pTableRef->getChild(0)->isToken()) ) + { + const OSQLParseNode* pNode = _pTableRef->getChild(nCount - (nCount == 2 ? 1 : 2)); + OSL_ENSURE(pNode && (pNode->getKnownRuleID() == OSQLParseNode::table_primary_as_range_column + || pNode->getKnownRuleID() == OSQLParseNode::range_variable) + ,"SQL grammar changed!"); + if ( !pNode->isLeaf() ) + sTableRange = pNode->getChild(1)->getTokenValue(); + } // if ( nCount == 2 || nCount == 3 ) + + return sTableRange; +} + +OSQLParseNodesContainer::OSQLParseNodesContainer() +{ +} + +OSQLParseNodesContainer::~OSQLParseNodesContainer() +{ +} + +void OSQLParseNodesContainer::push_back(OSQLParseNode* _pNode) +{ + ::osl::MutexGuard aGuard(m_aMutex); + m_aNodes.push_back(_pNode); +} + +void OSQLParseNodesContainer::erase(OSQLParseNode* _pNode) +{ + ::osl::MutexGuard aGuard(m_aMutex); + if ( !m_aNodes.empty() ) + { + std::vector< OSQLParseNode* >::iterator aFind = std::find(m_aNodes.begin(), m_aNodes.end(),_pNode); + if ( aFind != m_aNodes.end() ) + m_aNodes.erase(aFind); + } +} + +void OSQLParseNodesContainer::clear() +{ + ::osl::MutexGuard aGuard(m_aMutex); + m_aNodes.clear(); +} + +void OSQLParseNodesContainer::clearAndDelete() +{ + ::osl::MutexGuard aGuard(m_aMutex); + // clear the garbage collector + while ( !m_aNodes.empty() ) + { + OSQLParseNode* pNode = m_aNodes[0]; + while ( pNode->getParent() ) + { + pNode = pNode->getParent(); + } + delete pNode; + } +} +} // namespace connectivity + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/resource/sharedresources.cxx b/connectivity/source/resource/sharedresources.cxx new file mode 100644 index 000000000..3f7062f6b --- /dev/null +++ b/connectivity/source/resource/sharedresources.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 <resource/sharedresources.hxx> + +#include <unotools/resmgr.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <sal/log.hxx> + +namespace connectivity +{ + namespace { + + class SharedResources_Impl + { + private: + static SharedResources_Impl* s_pInstance; + static oslInterlockedCount s_nClients; + + private: + std::locale m_aLocale; + + public: + static void registerClient(); + static void revokeClient(); + + static SharedResources_Impl& + getInstance(); + + OUString getResourceString(const char* pId); + + private: + SharedResources_Impl(); + + static ::osl::Mutex& getMutex() + { + static ::osl::Mutex s_aMutex; + return s_aMutex; + } + }; + + } + + SharedResources_Impl* SharedResources_Impl::s_pInstance( nullptr ); + oslInterlockedCount SharedResources_Impl::s_nClients( 0 ); + + SharedResources_Impl::SharedResources_Impl() + : m_aLocale(Translate::Create("cnr")) + { + } + + OUString SharedResources_Impl::getResourceString(const char* pId) + { + return Translate::get(pId, m_aLocale); + } + + void SharedResources_Impl::registerClient() + { + osl_atomic_increment( &s_nClients ); + } + + void SharedResources_Impl::revokeClient() + { + ::osl::MutexGuard aGuard( getMutex() ); + if ( 0 == osl_atomic_decrement( &s_nClients ) ) + { + delete s_pInstance; + s_pInstance = nullptr; + } + } + + + SharedResources_Impl& SharedResources_Impl::getInstance() + { + ::osl::MutexGuard aGuard( getMutex() ); + OSL_ENSURE( s_nClients > 0, "SharedResources_Impl::getInstance: no active clients!" ); + + if ( !s_pInstance ) + s_pInstance = new SharedResources_Impl; + + return *s_pInstance; + } + + namespace + { + size_t lcl_substitute( OUString& _inout_rString, + const char* _pAsciiPattern, const OUString& _rReplace ) + { + size_t nOccurrences = 0; + + OUString sPattern( OUString::createFromAscii( _pAsciiPattern ) ); + sal_Int32 nIndex = 0; + while ( ( nIndex = _inout_rString.indexOf( sPattern ) ) > -1 ) + { + ++nOccurrences; + _inout_rString = _inout_rString.replaceAt( nIndex, sPattern.getLength(), _rReplace ); + } + + return nOccurrences; + } + } + + SharedResources::SharedResources() + { + SharedResources_Impl::registerClient(); + } + + + SharedResources::~SharedResources() + { + SharedResources_Impl::revokeClient(); + } + + + OUString SharedResources::getResourceString(const char* pResId) const + { + return SharedResources_Impl::getInstance().getResourceString(pResId); + } + + + OUString SharedResources::getResourceStringWithSubstitution(const char* pResId, + const char* _pAsciiPatternToReplace, const OUString& _rStringToSubstitute ) const + { + OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) ); + if ( !lcl_substitute( sString, _pAsciiPatternToReplace, _rStringToSubstitute ) ) + SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace << " with " << _rStringToSubstitute); + return sString; + } + + + OUString SharedResources::getResourceStringWithSubstitution(const char* pResId, + const char* _pAsciiPatternToReplace1, const OUString& _rStringToSubstitute1, + const char* _pAsciiPatternToReplace2, const OUString& _rStringToSubstitute2 ) const + { + OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) ); + if( !lcl_substitute( sString, _pAsciiPatternToReplace1, _rStringToSubstitute1 ) ) + SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace1 << " with " << _rStringToSubstitute1); + if( !lcl_substitute( sString, _pAsciiPatternToReplace2, _rStringToSubstitute2 ) ) + SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace2 << " with " << _rStringToSubstitute2); + return sString; + } + + + OUString SharedResources::getResourceStringWithSubstitution(const char* pResId, + const char* _pAsciiPatternToReplace1, const OUString& _rStringToSubstitute1, + const char* _pAsciiPatternToReplace2, const OUString& _rStringToSubstitute2, + const char* _pAsciiPatternToReplace3, const OUString& _rStringToSubstitute3 ) const + { + OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) ); + if( !lcl_substitute( sString, _pAsciiPatternToReplace1, _rStringToSubstitute1 ) ) + SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace1 << " with " << _rStringToSubstitute1); + if( !lcl_substitute( sString, _pAsciiPatternToReplace2, _rStringToSubstitute2 ) ) + SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace2 << " with " << _rStringToSubstitute2); + if( !lcl_substitute( sString, _pAsciiPatternToReplace3, _rStringToSubstitute3 ) ) + SAL_WARN("connectivity.resource", "Unable to substitute " << _pAsciiPatternToReplace3 << " with " << _rStringToSubstitute3); + return sString; + } + + OUString SharedResources::getResourceStringWithSubstitution(const char* pResId, + const std::vector< std::pair<const char* , OUString > >& _rStringToSubstitutes) const + { + OUString sString( SharedResources_Impl::getInstance().getResourceString(pResId) ); + for(const auto& [rPattern, rReplace] : _rStringToSubstitutes) + if( !lcl_substitute( sString, rPattern, rReplace ) ) + SAL_WARN("connectivity.resource", "Unable to substitute " << rPattern << " with " << rReplace); + + return sString; + } + + +} // namespace connectivity + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VCatalog.cxx b/connectivity/source/sdbcx/VCatalog.cxx new file mode 100644 index 000000000..b30519fca --- /dev/null +++ b/connectivity/source/sdbcx/VCatalog.cxx @@ -0,0 +1,211 @@ +/* -*- 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 <comphelper/types.hxx> +#include <sdbcx/VCatalog.hxx> +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XRow.hpp> +#include <connectivity/sdbcx/VDescriptor.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <TConnection.hxx> +#include <connectivity/dbtools.hxx> + +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +IMPLEMENT_SERVICE_INFO(OCatalog,"com.sun.star.comp.connectivity.OCatalog","com.sun.star.sdbcx.DatabaseDefinition") + +OCatalog::OCatalog(const Reference< XConnection> &_xConnection) : OCatalog_BASE(m_aMutex) +{ + try + { + m_xMetaData = _xConnection->getMetaData(); + } + catch(const Exception&) + { + OSL_FAIL("No Metadata available!"); + } +} + +OCatalog::~OCatalog() +{ +} + +void SAL_CALL OCatalog::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + if(m_pTables) + m_pTables->disposing(); + if(m_pViews) + m_pViews->disposing(); + if(m_pGroups) + m_pGroups->disposing(); + if(m_pUsers) + m_pUsers->disposing(); + + OCatalog_BASE::disposing(); +} + +// XTablesSupplier +Reference< XNameAccess > SAL_CALL OCatalog::getTables( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OCatalog_BASE::rBHelper.bDisposed); + + try + { + if(!m_pTables) + refreshTables(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pTables.get(); +} + +// XViewsSupplier +Reference< XNameAccess > SAL_CALL OCatalog::getViews( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OCatalog_BASE::rBHelper.bDisposed); + + try + { + if(!m_pViews) + refreshViews(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pViews.get(); +} + +// XUsersSupplier +Reference< XNameAccess > SAL_CALL OCatalog::getUsers( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OCatalog_BASE::rBHelper.bDisposed); + + try + { + if(!m_pUsers) + refreshUsers(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pUsers.get(); +} + +// XGroupsSupplier +Reference< XNameAccess > SAL_CALL OCatalog::getGroups( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OCatalog_BASE::rBHelper.bDisposed); + + try + { + if(!m_pGroups) + refreshGroups(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pGroups.get(); +} + +OUString OCatalog::buildName(const Reference< XRow >& _xRow) +{ + OUString sCatalog = _xRow->getString(1); + if ( _xRow->wasNull() ) + sCatalog.clear(); + OUString sSchema = _xRow->getString(2); + if ( _xRow->wasNull() ) + sSchema.clear(); + OUString sTable = _xRow->getString(3); + if ( _xRow->wasNull() ) + sTable.clear(); + + OUString sComposedName( + ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation ) ); + return sComposedName; +} + +void OCatalog::fillNames(Reference< XResultSet >& _xResult,::std::vector< OUString>& _rNames) +{ + if ( _xResult.is() ) + { + _rNames.reserve(20); + Reference< XRow > xRow(_xResult,UNO_QUERY); + while ( _xResult->next() ) + { + _rNames.push_back( buildName(xRow) ); + } + xRow.clear(); + ::comphelper::disposeComponent(_xResult); + } +} + +void ODescriptor::construct() +{ + sal_Int32 nAttrib = isNew() ? 0 : css::beans::PropertyAttribute::READONLY; + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME), PROPERTY_ID_NAME ,nAttrib,&m_Name,::cppu::UnoType<OUString>::get()); +} + +ODescriptor::~ODescriptor() +{ +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VCollection.cxx b/connectivity/source/sdbcx/VCollection.cxx new file mode 100644 index 000000000..d7a716a59 --- /dev/null +++ b/connectivity/source/sdbcx/VCollection.cxx @@ -0,0 +1,583 @@ +/* -*- 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 <algorithm> +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <connectivity/sdbcx/VCollection.hxx> +#include <connectivity/sdbcx/VDescriptor.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <connectivity/dbexception.hxx> +#include <comphelper/enumhelper.hxx> +#include <comphelper/types.hxx> +#include <comphelper/property.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <TConnection.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + +using namespace connectivity::sdbcx; +using namespace connectivity; +using namespace comphelper; +using namespace ::cppu; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; + +namespace +{ + template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection + { + typedef std::multimap< OUString, T , ::comphelper::UStringMixLess> ObjectMap; + typedef typename ObjectMap::iterator ObjectIter; + typedef typename ObjectMap::value_type ObjectEntry; + + // private: + // this combination of map and vector is used to have a fast name and index access + std::vector< ObjectIter > m_aElements; // hold the iterators which point to map + ObjectMap m_aNameMap; // hold the elements and a name + public: + OHardRefMap(bool _bCase) + : m_aNameMap(_bCase) + { + } + + virtual bool exists(const OUString& _sName ) override + { + return m_aNameMap.find(_sName) != m_aNameMap.end(); + } + + virtual bool empty() override + { + return m_aNameMap.empty(); + } + + virtual void swapAll() override + { + std::vector< ObjectIter >(m_aElements).swap(m_aElements); + ObjectMap(m_aNameMap).swap(m_aNameMap); + } + + virtual void swap() override + { + std::vector< ObjectIter >().swap(m_aElements); + + OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" ); + ObjectMap( m_aNameMap ).swap( m_aNameMap ); + // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before + // swapping. This way, it's ensured that the compare object held by these maps is preserved + // during the swap. If we would not do this, the UStringMixLess instance which is used would be + // default constructed (instead of being constructed from the same instance in m_aNameMap), and + // it's case-sensitive flag would have an unpredictable value. + } + + virtual void clear() override + { + m_aElements.clear(); + m_aNameMap.clear(); + } + + virtual void insert(const OUString& _sName,const ObjectType& _xObject) override + { + m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject))); + } + + virtual void reFill(const ::std::vector< OUString> &_rVector) override + { + OSL_ENSURE(m_aNameMap.empty(),"OCollection::reFill: collection isn't empty"); + m_aElements.reserve(_rVector.size()); + + for (auto const& elem : _rVector) + m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(elem,ObjectType()))); + } + + virtual bool rename(const OUString& _sOldName, const OUString& _sNewName) override + { + bool bRet = false; + ObjectIter aIter = m_aNameMap.find(_sOldName); + if ( aIter != m_aNameMap.end() ) + { + typename std::vector< ObjectIter >::iterator aFind = std::find(m_aElements.begin(),m_aElements.end(),aIter); + if(m_aElements.end() != aFind) + { + (*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second)); + m_aNameMap.erase(aIter); + + bRet = true; + } + } + return bRet; + } + + virtual sal_Int32 size() override + { + return static_cast<sal_Int32>(m_aNameMap.size()); + } + + virtual Sequence< OUString > getElementNames() override + { + Sequence< OUString > aNameList(m_aElements.size()); + + OUString* pStringArray = aNameList.getArray(); + for(const auto& rIter : m_aElements) + { + *pStringArray = rIter->first; + ++pStringArray; + } + + return aNameList; + } + + virtual OUString getName(sal_Int32 _nIndex) override + { + return m_aElements[_nIndex]->first; + } + + virtual void disposeAndErase(sal_Int32 _nIndex) override + { + OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!"); + Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY); + ::comphelper::disposeComponent(xComp); + m_aElements[_nIndex]->second = T(); + + OUString sName = m_aElements[_nIndex]->first; + m_aElements.erase(m_aElements.begin()+_nIndex); + m_aNameMap.erase(sName); + } + + virtual void disposeElements() override + { + for (auto & name : m_aNameMap) + { + Reference<XComponent> xComp(name.second.get(),UNO_QUERY); + if ( xComp.is() ) + { + ::comphelper::disposeComponent(xComp); + name.second = T(); + } + } + m_aElements.clear(); + m_aNameMap.clear(); + } + + virtual sal_Int32 findColumn( const OUString& columnName ) override + { + ObjectIter aIter = m_aNameMap.find(columnName); + OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!"); + return m_aElements.size() - (m_aElements.end() - std::find(m_aElements.begin(),m_aElements.end(),aIter)); + } + + virtual ObjectType getObject(sal_Int32 _nIndex) override + { + OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!"); + return m_aElements[_nIndex]->second; + } + + virtual ObjectType getObject(const OUString& columnName) override + { + return m_aNameMap.find(columnName)->second; + } + + virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject) override + { + OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!"); + m_aElements[_nIndex]->second = _xObject; + } + + bool isCaseSensitive() const override + { + return m_aNameMap.key_comp().isCaseSensitive(); + } + + }; +} + +IObjectCollection::~IObjectCollection() {} + +IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container") + +OCollection::OCollection(::cppu::OWeakObject& _rParent + , bool _bCase + , ::osl::Mutex& _rMutex + , const ::std::vector< OUString> &_rVector + , bool _bUseIndexOnly + , bool _bUseHardRef) + :m_aContainerListeners(_rMutex) + ,m_aRefreshListeners(_rMutex) + ,m_rParent(_rParent) + ,m_rMutex(_rMutex) + ,m_bUseIndexOnly(_bUseIndexOnly) +{ + if ( _bUseHardRef ) + { + m_pElements.reset(new OHardRefMap< ObjectType >(_bCase)); + } + else + { + m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase)); + } + m_pElements->reFill(_rVector); +} + +OCollection::~OCollection() +{ +} + +Any SAL_CALL OCollection::queryInterface( const Type & rType ) +{ + if ( m_bUseIndexOnly && rType == cppu::UnoType<XNameAccess>::get() ) + { + return Any(); + } + return OCollectionBase::queryInterface( rType ); +} + +Sequence< Type > SAL_CALL OCollection::getTypes() +{ + if ( m_bUseIndexOnly ) + { + Sequence< Type > aTypes(OCollectionBase::getTypes()); + Type* pBegin = aTypes.getArray(); + Type* pEnd = pBegin + aTypes.getLength(); + + std::vector<Type> aOwnTypes; + aOwnTypes.reserve(aTypes.getLength()); + Type aType = cppu::UnoType<XNameAccess>::get(); + for(;pBegin != pEnd; ++pBegin) + { + if ( *pBegin != aType ) + aOwnTypes.push_back(*pBegin); + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); + } + return OCollectionBase::getTypes( ); +} + +void OCollection::clear_NoDispose() +{ + ::osl::MutexGuard aGuard(m_rMutex); + + m_pElements->clear(); + m_pElements->swapAll(); +} + + +void OCollection::disposing() +{ + m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this))); + m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this))); + + ::osl::MutexGuard aGuard(m_rMutex); + + disposeElements(); + + m_pElements->swap(); +} + +Any SAL_CALL OCollection::getByIndex( sal_Int32 Index ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + if (Index < 0 || Index >= m_pElements->size() ) + throw IndexOutOfBoundsException(OUString::number(Index),static_cast<XTypeProvider*>(this)); + + return makeAny(getObject(Index)); +} + +Any SAL_CALL OCollection::getByName( const OUString& aName ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + + if ( !m_pElements->exists(aName) ) + { + ::connectivity::SharedResources aResources; + const OUString sError( aResources.getResourceStringWithSubstitution( + STR_NO_ELEMENT_NAME, + "$name$", aName + ) ); + throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) ); + } + + return makeAny(getObject(m_pElements->findColumn(aName))); +} + +Sequence< OUString > SAL_CALL OCollection::getElementNames( ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + return m_pElements->getElementNames(); +} + +void SAL_CALL OCollection::refresh( ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + + disposeElements(); + + impl_refresh(); + EventObject aEvt(static_cast<XTypeProvider*>(this)); + m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt ); +} + +void OCollection::reFill(const ::std::vector< OUString> &_rVector) +{ + m_pElements->reFill(_rVector); +} + +// XDataDescriptorFactory +Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor( ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + + return createDescriptor(); +} + +OUString OCollection::getNameForObject(const ObjectType& _xObject) +{ + OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!"); + OUString sName; + _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName; + return sName; +} + +// XAppend +void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor ) +{ + ::osl::ClearableMutexGuard aGuard(m_rMutex); + + OUString sName = getNameForObject( descriptor ); + + if ( m_pElements->exists(sName) ) + throw ElementExistException(sName,static_cast<XTypeProvider*>(this)); + + ObjectType xNewlyCreated = appendObject( sName, descriptor ); + if ( !xNewlyCreated.is() ) + throw RuntimeException(); + + ODescriptor* pDescriptor = comphelper::getUnoTunnelImplementation<ODescriptor>( xNewlyCreated ); + if ( pDescriptor ) + pDescriptor->setNew( false ); + + sName = getNameForObject( xNewlyCreated ); + if ( !m_pElements->exists( sName ) ) // this may happen when the derived class included it itself + m_pElements->insert( sName, xNewlyCreated ); + + // notify our container listeners + ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(sName), makeAny(xNewlyCreated), Any()); + aGuard.clear(); + m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent ); +} + +// XDrop +void SAL_CALL OCollection::dropByName( const OUString& elementName ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + + if ( !m_pElements->exists(elementName) ) + throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this)); + + dropImpl(m_pElements->findColumn(elementName)); +} + +void SAL_CALL OCollection::dropByIndex( sal_Int32 index ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + if(index <0 || index >= getCount()) + throw IndexOutOfBoundsException(OUString::number(index),static_cast<XTypeProvider*>(this)); + + dropImpl(index); +} + +void OCollection::dropImpl(sal_Int32 _nIndex, bool _bReallyDrop) +{ + OUString elementName = m_pElements->getName(_nIndex); + + if ( _bReallyDrop ) + dropObject(_nIndex,elementName); + + m_pElements->disposeAndErase(_nIndex); + + // notify our container listeners + notifyElementRemoved(elementName); +} + +void OCollection::notifyElementRemoved(const OUString& _sName) +{ + ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sName), Any(), Any()); + // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment + OInterfaceIteratorHelper2 aListenerLoop(m_aContainerListeners); + while (aListenerLoop.hasMoreElements()) + static_cast<XContainerListener*>(aListenerLoop.next())->elementRemoved(aEvent); +} + +sal_Int32 SAL_CALL OCollection::findColumn( const OUString& columnName ) +{ + if ( !m_pElements->exists(columnName) ) + { + ::dbtools::throwInvalidColumnException( columnName, static_cast< XIndexAccess*>(this) ); +#if !(defined(_MSC_VER) && defined(ENABLE_LTO)) + assert(false); +#endif + } + + return m_pElements->findColumn(columnName) + 1; // because columns start at one +} + +Reference< XEnumeration > SAL_CALL OCollection::createEnumeration( ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + return new OEnumerationByIndex( static_cast< XIndexAccess*>(this)); +} + +void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener ) +{ + m_aContainerListeners.addInterface(_rxListener); +} + + +void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener ) +{ + m_aContainerListeners.removeInterface(_rxListener); +} + +void SAL_CALL OCollection::acquire() throw() +{ + m_rParent.acquire(); +} + +void SAL_CALL OCollection::release() throw() +{ + m_rParent.release(); +} + +Type SAL_CALL OCollection::getElementType( ) +{ + return cppu::UnoType<XPropertySet>::get(); +} + +sal_Bool SAL_CALL OCollection::hasElements( ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + return !m_pElements->empty(); +} + +sal_Int32 SAL_CALL OCollection::getCount( ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + return m_pElements->size(); +} + +sal_Bool SAL_CALL OCollection::hasByName( const OUString& aName ) +{ + ::osl::MutexGuard aGuard(m_rMutex); + return m_pElements->exists(aName); +} + +void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l ) +{ + m_aRefreshListeners.addInterface(l); +} + +void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l ) +{ + m_aRefreshListeners.removeInterface(l); +} + +void OCollection::insertElement(const OUString& _sElementName,const ObjectType& _xElement) +{ + OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists"); + if ( !m_pElements->exists(_sElementName) ) + m_pElements->insert(_sElementName,_xElement); +} + +void OCollection::renameObject(const OUString& _sOldName, const OUString& _sNewName) +{ + OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist"); + OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists"); + OSL_ENSURE(!_sNewName.isEmpty(),"New name must not be empty!"); + OSL_ENSURE(!_sOldName.isEmpty(),"Old name must not be empty!"); + + if ( m_pElements->rename(_sOldName,_sNewName) ) + { + ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sNewName), makeAny(m_pElements->getObject(_sNewName)),makeAny(_sOldName)); + // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment + OInterfaceIteratorHelper2 aListenerLoop(m_aContainerListeners); + while (aListenerLoop.hasMoreElements()) + static_cast<XContainerListener*>(aListenerLoop.next())->elementReplaced(aEvent); + } +} + +ObjectType OCollection::getObject(sal_Int32 _nIndex) +{ + ObjectType xName = m_pElements->getObject(_nIndex); + if ( !xName.is() ) + { + try + { + xName = createObject(m_pElements->getName(_nIndex)); + } + catch(const SQLException& e) + { + css::uno::Any anyEx = cppu::getCaughtException(); + try + { + dropImpl(_nIndex,false); + } + catch(const Exception& ) + { + } + throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),anyEx); + } + m_pElements->setObject(_nIndex,xName); + } + return xName; +} + +void OCollection::disposeElements() +{ + m_pElements->disposeElements(); +} + +Reference< XPropertySet > OCollection::createDescriptor() +{ + OSL_FAIL("createDescriptor() needs to be overridden when used!"); + throw SQLException(); +} + +ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor ) +{ + ObjectType xNewDescriptor( createDescriptor() ); + ::comphelper::copyProperties( _descriptor, xNewDescriptor ); + return xNewDescriptor; +} + +ObjectType OCollection::appendObject( const OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor ) +{ + return cloneDescriptor( descriptor ); +} + +void OCollection::dropObject(sal_Int32 /*_nPos*/, const OUString& /*_sElementName*/) +{ +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VColumn.cxx b/connectivity/source/sdbcx/VColumn.cxx new file mode 100644 index 000000000..239934531 --- /dev/null +++ b/connectivity/source/sdbcx/VColumn.cxx @@ -0,0 +1,220 @@ +/* -*- 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/sdbcx/VColumn.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <TConnection.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> + +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace cppu; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; + + +OUString SAL_CALL OColumn::getImplementationName( ) +{ + if(isNew()) + return "com.sun.star.sdbcx.VColumnDescriptor"; + return "com.sun.star.sdbcx.VColumn"; +} + +css::uno::Sequence< OUString > SAL_CALL OColumn::getSupportedServiceNames( ) +{ + return { isNew()?OUString("com.sun.star.sdbcx.ColumnDescriptor"):OUString("com.sun.star.sdbcx.Column") }; +} + +sal_Bool SAL_CALL OColumn::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +OColumn::OColumn(bool _bCase) + :OColumnDescriptor_BASE(m_aMutex) + ,ODescriptor(OColumnDescriptor_BASE::rBHelper,_bCase,true) + ,m_IsNullable(ColumnValue::NULLABLE) + ,m_Precision(0) + ,m_Scale(0) + ,m_Type(0) + ,m_IsAutoIncrement(false) + ,m_IsRowVersion(false) + ,m_IsCurrency(false) +{ + construct(); +} + +OColumn::OColumn( const OUString& Name, + const OUString& TypeName, + const OUString& DefaultValue, + const OUString& Description, + sal_Int32 IsNullable, + sal_Int32 Precision, + sal_Int32 Scale, + sal_Int32 Type, + bool IsAutoIncrement, + bool IsRowVersion, + bool IsCurrency, + bool _bCase, + const OUString& CatalogName, + const OUString& SchemaName, + const OUString& TableName) + :OColumnDescriptor_BASE(m_aMutex) + ,ODescriptor(OColumnDescriptor_BASE::rBHelper,_bCase) + ,m_TypeName(TypeName) + ,m_Description(Description) + ,m_DefaultValue(DefaultValue) + ,m_IsNullable(IsNullable) + ,m_Precision(Precision) + ,m_Scale(Scale) + ,m_Type(Type) + ,m_IsAutoIncrement(IsAutoIncrement) + ,m_IsRowVersion(IsRowVersion) + ,m_IsCurrency(IsCurrency) + ,m_CatalogName(CatalogName) + ,m_SchemaName(SchemaName) + ,m_TableName(TableName) +{ + m_Name = Name; + + construct(); +} + +OColumn::~OColumn() +{ +} + +::cppu::IPropertyArrayHelper* OColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& SAL_CALL OColumn::getInfoHelper() +{ + return *OColumn_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +void SAL_CALL OColumn::acquire() throw() +{ + OColumnDescriptor_BASE::acquire(); +} + +void SAL_CALL OColumn::release() throw() +{ + OColumnDescriptor_BASE::release(); +} + +Any SAL_CALL OColumn::queryInterface( const Type & rType ) +{ + Any aRet = ODescriptor::queryInterface( rType); + if(!aRet.hasValue()) + { + if(!isNew()) + aRet = OColumn_BASE::queryInterface(rType); + if(!aRet.hasValue()) + aRet = OColumnDescriptor_BASE::queryInterface( rType); + } + return aRet; +} + +Sequence< Type > SAL_CALL OColumn::getTypes( ) +{ + if(isNew()) + return ::comphelper::concatSequences(ODescriptor::getTypes(),OColumnDescriptor_BASE::getTypes()); + + return ::comphelper::concatSequences(ODescriptor::getTypes(),OColumn_BASE::getTypes(),OColumnDescriptor_BASE::getTypes()); +} + +void OColumn::construct() +{ + ODescriptor::construct(); + + sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY; + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME), PROPERTY_ID_TYPENAME, nAttrib, &m_TypeName, cppu::UnoType<decltype(m_TypeName)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION), PROPERTY_ID_DESCRIPTION, nAttrib, &m_Description, cppu::UnoType<decltype(m_Description)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE), PROPERTY_ID_DEFAULTVALUE, nAttrib, &m_DefaultValue, cppu::UnoType<decltype(m_DefaultValue)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION), PROPERTY_ID_PRECISION, nAttrib, &m_Precision, cppu::UnoType<decltype(m_Precision)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib, &m_Type, cppu::UnoType<decltype(m_Type)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE), PROPERTY_ID_SCALE, nAttrib, &m_Scale, cppu::UnoType<decltype(m_Scale)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE), PROPERTY_ID_ISNULLABLE, nAttrib, &m_IsNullable, cppu::UnoType<decltype(m_IsNullable)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT), PROPERTY_ID_ISAUTOINCREMENT, nAttrib, &m_IsAutoIncrement, cppu::UnoType<bool>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISROWVERSION), PROPERTY_ID_ISROWVERSION, nAttrib, &m_IsRowVersion, cppu::UnoType<bool>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY), PROPERTY_ID_ISCURRENCY, nAttrib, &m_IsCurrency, cppu::UnoType<bool>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME, nAttrib, &m_CatalogName, cppu::UnoType<decltype(m_CatalogName)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib, &m_SchemaName, cppu::UnoType<decltype(m_SchemaName)>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TABLENAME), PROPERTY_ID_TABLENAME, nAttrib, &m_TableName, cppu::UnoType<decltype(m_TableName)>::get()); +} + +void OColumn::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OColumnDescriptor_BASE::rBHelper.bDisposed); + +} + +Reference< XPropertySet > SAL_CALL OColumn::createDataDescriptor( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OColumnDescriptor_BASE::rBHelper.bDisposed); + + + OColumn* pNewColumn = new OColumn( m_Name, + m_TypeName, + m_DefaultValue, + m_Description, + m_IsNullable, + m_Precision, + m_Scale, + m_Type, + m_IsAutoIncrement, + m_IsRowVersion, + m_IsCurrency, + isCaseSensitive(), + m_CatalogName, + m_SchemaName, + m_TableName); + pNewColumn->setNew(true); + return pNewColumn; +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OColumn::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +// XNamed +OUString SAL_CALL OColumn::getName( ) +{ + return m_Name; +} + +void SAL_CALL OColumn::setName( const OUString& aName ) +{ + m_Name = aName; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VDescriptor.cxx b/connectivity/source/sdbcx/VDescriptor.cxx new file mode 100644 index 000000000..8a32a1b58 --- /dev/null +++ b/connectivity/source/sdbcx/VDescriptor.cxx @@ -0,0 +1,128 @@ +/* -*- 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/sdbcx/VDescriptor.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> + +#include <algorithm> + +namespace connectivity::sdbcx +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + + // = ODescriptor + + + ODescriptor::ODescriptor(::cppu::OBroadcastHelper& _rBHelper, bool _bCase, bool _bNew) + :ODescriptor_PBASE(_rBHelper) + ,m_aCase(_bCase) + ,m_bNew(_bNew) + { + } + + + // css::lang::XUnoTunnel + sal_Int64 SAL_CALL ODescriptor::getSomething( const Sequence< sal_Int8 >& rId ) + { + return (isUnoTunnelId<ODescriptor>(rId)) + ? reinterpret_cast< sal_Int64 >( this ) + : 0; + } + + + namespace + { + struct ResetROAttribute + { + void operator ()( Property& _rProperty ) const + { + _rProperty.Attributes &= ~PropertyAttribute::READONLY; + } + }; + struct SetROAttribute + { + void operator ()( Property& _rProperty ) const + { + _rProperty.Attributes |= PropertyAttribute::READONLY; + } + }; + } + + + ::cppu::IPropertyArrayHelper* ODescriptor::doCreateArrayHelper() const + { + Sequence< Property > aProperties; + describeProperties( aProperties ); + + if ( isNew() ) + std::for_each( aProperties.begin(), aProperties.end(), ResetROAttribute() ); + else + std::for_each( aProperties.begin(), aProperties.end(), SetROAttribute() ); + + return new ::cppu::OPropertyArrayHelper( aProperties ); + } + + + bool ODescriptor::isNew( const Reference< XInterface >& _rxDescriptor ) + { + ODescriptor* pImplementation = comphelper::getUnoTunnelImplementation<ODescriptor>( _rxDescriptor ); + return pImplementation && pImplementation->isNew(); + } + + + Sequence< sal_Int8 > ODescriptor::getUnoTunnelId() + { + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); + } + + + Any SAL_CALL ODescriptor::queryInterface( const Type & rType ) + { + Any aRet = ::cppu::queryInterface(rType,static_cast< XUnoTunnel*> (this)); + return aRet.hasValue() ? aRet : ODescriptor_PBASE::queryInterface(rType); + } + + + void ODescriptor::setNew(bool _bNew) + { + m_bNew = _bNew; + } + + + Sequence< Type > SAL_CALL ODescriptor::getTypes( ) + { + ::cppu::OTypeCollection aTypes( cppu::UnoType<XMultiPropertySet>::get(), + cppu::UnoType<XFastPropertySet>::get(), + cppu::UnoType<XPropertySet>::get(), + cppu::UnoType<XUnoTunnel>::get()); + return aTypes.getTypes(); + } + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VGroup.cxx b/connectivity/source/sdbcx/VGroup.cxx new file mode 100644 index 000000000..ed11a6175 --- /dev/null +++ b/connectivity/source/sdbcx/VGroup.cxx @@ -0,0 +1,166 @@ +/* -*- 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 <sdbcx/VGroup.hxx> +#include <comphelper/sequence.hxx> +#include <connectivity/dbexception.hxx> + + +using namespace ::connectivity::sdbcx; +using namespace ::connectivity; +using namespace ::dbtools; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +IMPLEMENT_SERVICE_INFO(OGroup,"com.sun.star.sdbcx.VGroup","com.sun.star.sdbcx.Group"); + +OGroup::OGroup(bool _bCase) : OGroup_BASE(m_aMutex) + , ODescriptor(OGroup_BASE::rBHelper,_bCase) +{ +} + +OGroup::OGroup(const OUString& Name, bool _bCase) : OGroup_BASE(m_aMutex) + ,ODescriptor(OGroup_BASE::rBHelper,_bCase) +{ + m_Name = Name; +} + +OGroup::~OGroup() +{ +} + +Any SAL_CALL OGroup::queryInterface( const Type & rType ) +{ + Any aRet = ODescriptor::queryInterface( rType); + return aRet.hasValue() ? aRet : OGroup_BASE::queryInterface( rType); +} + +Sequence< Type > SAL_CALL OGroup::getTypes( ) +{ + return ::comphelper::concatSequences(ODescriptor::getTypes(),OGroup_BASE::getTypes()); +} + +void OGroup::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + + if(m_pUsers) + m_pUsers->disposing(); +} + +::cppu::IPropertyArrayHelper* OGroup::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +::cppu::IPropertyArrayHelper & OGroup::getInfoHelper() +{ + return *getArrayHelper(); +} + +Reference< XNameAccess > SAL_CALL OGroup::getUsers( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OGroup_BASE::rBHelper.bDisposed); + + try + { + if ( !m_pUsers ) + refreshUsers(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pUsers.get(); +} + + +sal_Int32 SAL_CALL OGroup::getPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OGroup_BASE::rBHelper.bDisposed); + + return 0; +} + +sal_Int32 SAL_CALL OGroup::getGrantablePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OGroup_BASE::rBHelper.bDisposed); + + return 0; +} + +void SAL_CALL OGroup::grantPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OGroup_BASE::rBHelper.bDisposed); + throwFeatureNotImplementedSQLException( "XAuthorizable::grantPrivileges", *this ); +} + +void SAL_CALL OGroup::revokePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OGroup_BASE::rBHelper.bDisposed); + throwFeatureNotImplementedSQLException( "XAuthorizable::revokePrivileges", *this ); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OGroup::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +OUString SAL_CALL OGroup::getName( ) +{ + return m_Name; +} + +void SAL_CALL OGroup::setName( const OUString& /*aName*/ ) +{ + throwFeatureNotImplementedRuntimeException( "XNamed::setName", *this ); +} + +// XInterface +void SAL_CALL OGroup::acquire() throw() +{ + OGroup_BASE::acquire(); +} + +void SAL_CALL OGroup::release() throw() +{ + OGroup_BASE::release(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VIndex.cxx b/connectivity/source/sdbcx/VIndex.cxx new file mode 100644 index 000000000..1649ff83a --- /dev/null +++ b/connectivity/source/sdbcx/VIndex.cxx @@ -0,0 +1,199 @@ +/* -*- 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 <sdbcx/VIndex.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <connectivity/dbexception.hxx> +#include <comphelper/sequence.hxx> +#include <connectivity/sdbcx/VCollection.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <TConnection.hxx> +#include <tools/diagnose_ex.h> + +using namespace ::connectivity; +using namespace ::dbtools; +using namespace ::connectivity::sdbcx; +using namespace ::cppu; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + + +OUString SAL_CALL OIndex::getImplementationName( ) +{ + if(isNew()) + return "com.sun.star.sdbcx.VIndexDescriptor"; + return "com.sun.star.sdbcx.VIndex"; +} + +css::uno::Sequence< OUString > SAL_CALL OIndex::getSupportedServiceNames( ) +{ + return { isNew()?OUString("com.sun.star.sdbcx.IndexDescriptor"):OUString("com.sun.star.sdbcx.Index") }; +} + +sal_Bool SAL_CALL OIndex::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +OIndex::OIndex(bool _bCase) : ODescriptor_BASE(m_aMutex) + , ODescriptor(ODescriptor_BASE::rBHelper,_bCase,true) + ,m_IsUnique(false) + ,m_IsPrimaryKeyIndex(false) + ,m_IsClustered(false) +{ +} + +OIndex::OIndex( const OUString& Name, + const OUString& Catalog, + bool _isUnique, + bool _isPrimaryKeyIndex, + bool _isClustered, + bool _bCase) : ODescriptor_BASE(m_aMutex) + ,ODescriptor(ODescriptor_BASE::rBHelper, _bCase) + ,m_Catalog(Catalog) + ,m_IsUnique(_isUnique) + ,m_IsPrimaryKeyIndex(_isPrimaryKeyIndex) + ,m_IsClustered(_isClustered) +{ + m_Name = Name; +} + +OIndex::~OIndex( ) +{ +} + +::cppu::IPropertyArrayHelper* OIndex::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& SAL_CALL OIndex::getInfoHelper() +{ + return *OIndex_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +Any SAL_CALL OIndex::queryInterface( const Type & rType ) +{ + Any aRet = ODescriptor::queryInterface( rType); + if(!aRet.hasValue()) + { + if(!isNew()) + aRet = OIndex_BASE::queryInterface(rType); + if(!aRet.hasValue()) + aRet = ODescriptor_BASE::queryInterface( rType); + } + return aRet; +} + +Sequence< Type > SAL_CALL OIndex::getTypes( ) +{ + if(isNew()) + return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes()); + return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes(),OIndex_BASE::getTypes()); +} + +void OIndex::construct() +{ + ODescriptor::construct(); + + sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY; + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOG), PROPERTY_ID_CATALOG, nAttrib,&m_Catalog, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE), PROPERTY_ID_ISUNIQUE, nAttrib,&m_IsUnique, cppu::UnoType<bool>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISPRIMARYKEYINDEX),PROPERTY_ID_ISPRIMARYKEYINDEX, nAttrib,&m_IsPrimaryKeyIndex, cppu::UnoType<bool>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCLUSTERED), PROPERTY_ID_ISCLUSTERED, nAttrib,&m_IsClustered, cppu::UnoType<bool>::get()); +} + +void OIndex::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + + if(m_pColumns) + m_pColumns->disposing(); +} + +Reference< css::container::XNameAccess > SAL_CALL OIndex::getColumns( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(ODescriptor_BASE::rBHelper.bDisposed); + + try + { + if ( !m_pColumns ) + refreshColumns(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "connectivity.commontools", "OIndex::getColumns" ); + } + + return m_pColumns.get(); +} + +Reference< XPropertySet > SAL_CALL OIndex::createDataDescriptor( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(ODescriptor_BASE::rBHelper.bDisposed); + + + return this; +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OIndex::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +OUString SAL_CALL OIndex::getName( ) +{ + return m_Name; +} + +void SAL_CALL OIndex::setName( const OUString& /*aName*/ ) +{ +} + +// XInterface +void SAL_CALL OIndex::acquire() throw() +{ + ODescriptor_BASE::acquire(); +} + +void SAL_CALL OIndex::release() throw() +{ + ODescriptor_BASE::release(); +} + +void OIndex::refreshColumns() +{ +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VIndexColumn.cxx b/connectivity/source/sdbcx/VIndexColumn.cxx new file mode 100644 index 000000000..edd1ea93e --- /dev/null +++ b/connectivity/source/sdbcx/VIndexColumn.cxx @@ -0,0 +1,102 @@ +/* -*- 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 <sdbcx/VIndexColumn.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <TConnection.hxx> + +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; + +OUString SAL_CALL OIndexColumn::getImplementationName( ) +{ + if(isNew()) + return "com.sun.star.sdbcx.VIndexColumnDescriptor"; + return "com.sun.star.sdbcx.VIndexColumn"; +} + +css::uno::Sequence< OUString > SAL_CALL OIndexColumn::getSupportedServiceNames( ) +{ + return { isNew()?OUString("com.sun.star.sdbcx.IndexColumnDescriptor"):OUString("com.sun.star.sdbcx.IndexColumn") }; +} + +sal_Bool SAL_CALL OIndexColumn::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +OIndexColumn::OIndexColumn(bool _bCase) : OColumn(_bCase), m_IsAscending(true) +{ + construct(); +} + + +OIndexColumn::OIndexColumn( bool IsAscending, + const OUString& Name, + const OUString& TypeName, + const OUString& DefaultValue, + sal_Int32 IsNullable, + sal_Int32 Precision, + sal_Int32 Scale, + sal_Int32 Type, + bool _bCase, + const OUString& CatalogName, + const OUString& SchemaName, + const OUString& TableName + ) : OColumn(Name, + TypeName, + DefaultValue, + OUString(), + IsNullable, + Precision, + Scale, + Type, + false/*IsAutoIncrement*/, + false/*IsRowVersion*/, + false/*IsCurrency*/, + _bCase, + CatalogName, + SchemaName, + TableName) + , m_IsAscending(IsAscending) +{ + construct(); +} + +::cppu::IPropertyArrayHelper* OIndexColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& SAL_CALL OIndexColumn::getInfoHelper() +{ + return *OIndexColumn_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +void OIndexColumn::construct() +{ + sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY; + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISASCENDING), PROPERTY_ID_ISASCENDING, nAttrib,&m_IsAscending, cppu::UnoType<bool>::get()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VKey.cxx b/connectivity/source/sdbcx/VKey.cxx new file mode 100644 index 000000000..33e9340b5 --- /dev/null +++ b/connectivity/source/sdbcx/VKey.cxx @@ -0,0 +1,202 @@ +/* -*- 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 <sdbcx/VKey.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbc/KeyRule.hpp> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <connectivity/sdbcx/VCollection.hxx> +#include <TConnection.hxx> + +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + + +OUString SAL_CALL OKey::getImplementationName( ) +{ + if(isNew()) + return "com.sun.star.sdbcx.VKeyDescriptor"; + return "com.sun.star.sdbcx.VKey"; +} + +css::uno::Sequence< OUString > SAL_CALL OKey::getSupportedServiceNames( ) +{ + return { isNew()?OUString("com.sun.star.sdbcx.KeyDescriptor"):OUString("com.sun.star.sdbcx.Key") }; +} + +sal_Bool SAL_CALL OKey::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +OKey::OKey(bool _bCase) : ODescriptor_BASE(m_aMutex) + , ODescriptor(ODescriptor_BASE::rBHelper, _bCase, true) + , m_aProps(std::make_shared<KeyProperties>()) +{ +} + +OKey::OKey(const OUString& Name,const std::shared_ptr<KeyProperties>& _rProps, bool _bCase) +: ODescriptor_BASE(m_aMutex) + ,ODescriptor(ODescriptor_BASE::rBHelper, _bCase) + ,m_aProps(_rProps) +{ + m_Name = Name; +} +//OKey::OKey( const OUString& _Name, +// const OUString& _ReferencedTable, +// sal_Int32 _Type, +// sal_Int32 _UpdateRule, +// sal_Int32 _DeleteRule, +// sal_Bool _bCase) : ODescriptor_BASE(m_aMutex) +// ,ODescriptor(ODescriptor_BASE::rBHelper,_bCase) +// ,m_ReferencedTable(_ReferencedTable) +// ,m_Type(_Type) +// ,m_UpdateRule(_UpdateRule) +// ,m_DeleteRule(_DeleteRule) +// ,m_pColumns(NULL) +//{ +// m_Name = _Name; +//} + +OKey::~OKey( ) +{ +} + +Any SAL_CALL OKey::queryInterface( const Type & rType ) +{ + Any aRet = ODescriptor::queryInterface( rType); + if(!aRet.hasValue()) + { + if(!isNew()) + aRet = OKey_BASE::queryInterface(rType); + if(!aRet.hasValue()) + aRet = ODescriptor_BASE::queryInterface( rType); + } + + return aRet; +} + +Sequence< Type > SAL_CALL OKey::getTypes( ) +{ + if(isNew()) + return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes()); + + return ::comphelper::concatSequences(ODescriptor::getTypes(),ODescriptor_BASE::getTypes(),OKey_BASE::getTypes()); +} + +void OKey::construct() +{ + ODescriptor::construct(); + + sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY; + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REFERENCEDTABLE), PROPERTY_ID_REFERENCEDTABLE, nAttrib,&m_aProps->m_ReferencedTable, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib,&m_aProps->m_Type, ::cppu::UnoType<sal_Int32>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_UPDATERULE), PROPERTY_ID_UPDATERULE, nAttrib,&m_aProps->m_UpdateRule, ::cppu::UnoType<sal_Int32>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DELETERULE), PROPERTY_ID_DELETERULE, nAttrib,&m_aProps->m_DeleteRule, ::cppu::UnoType<sal_Int32>::get()); +} + +void SAL_CALL OKey::disposing() +{ + OPropertySetHelper::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + + if(m_pColumns) + m_pColumns->disposing(); + + ODescriptor_BASE::disposing(); +} + +::cppu::IPropertyArrayHelper* OKey::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & OKey::getInfoHelper() +{ + return *getArrayHelper(isNew() ? 1 : 0); +} + +Reference< css::container::XNameAccess > SAL_CALL OKey::getColumns( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(ODescriptor_BASE::rBHelper.bDisposed); + + try + { + if ( !m_pColumns ) + refreshColumns(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pColumns.get(); +} + +Reference< XPropertySet > SAL_CALL OKey::createDataDescriptor( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(ODescriptor_BASE::rBHelper.bDisposed); + + + return this; +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OKey::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +OUString SAL_CALL OKey::getName( ) +{ + return m_Name; +} + +void SAL_CALL OKey::setName( const OUString& /*aName*/ ) +{ +} + +// XInterface +void SAL_CALL OKey::acquire() throw() +{ + ODescriptor_BASE::acquire(); +} + +void SAL_CALL OKey::release() throw() +{ + ODescriptor_BASE::release(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VKeyColumn.cxx b/connectivity/source/sdbcx/VKeyColumn.cxx new file mode 100644 index 000000000..b6f69e65c --- /dev/null +++ b/connectivity/source/sdbcx/VKeyColumn.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 <sdbcx/VKeyColumn.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <TConnection.hxx> + +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace cppu; + +OUString SAL_CALL OKeyColumn::getImplementationName( ) +{ + if(isNew()) + return "com.sun.star.sdbcx.VKeyColumnDescriptor"; + return "com.sun.star.sdbcx.VKeyColumn"; +} + +css::uno::Sequence< OUString > SAL_CALL OKeyColumn::getSupportedServiceNames( ) +{ + return { isNew()?OUString("com.sun.star.sdbcx.KeyColumnDescriptor"):OUString("com.sun.star.sdbcx.KeyColumn") }; +} + +sal_Bool SAL_CALL OKeyColumn::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +OKeyColumn::OKeyColumn(bool _bCase) : OColumn(_bCase) +{ + construct(); +} + +OKeyColumn::OKeyColumn( const OUString& ReferencedColumn, + const OUString& Name, + const OUString& TypeName, + const OUString& DefaultValue, + sal_Int32 IsNullable, + sal_Int32 Precision, + sal_Int32 Scale, + sal_Int32 Type, + bool _bCase, + const OUString& CatalogName, + const OUString& SchemaName, + const OUString& TableName + ) : OColumn(Name, + TypeName, + DefaultValue, + OUString(), + IsNullable, + Precision, + Scale, + Type, + false/*IsAutoIncrement*/, + false/*IsRowVersion*/, + false/*IsCurrency*/, + _bCase, + CatalogName, + SchemaName, + TableName) + , m_ReferencedColumn(ReferencedColumn) +{ + construct(); +} + +OKeyColumn::~OKeyColumn() +{ +} + +::cppu::IPropertyArrayHelper* OKeyColumn::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper& SAL_CALL OKeyColumn::getInfoHelper() +{ + return *OKeyColumn_PROP::getArrayHelper(isNew() ? 1 : 0); +} + +void OKeyColumn::construct() +{ + sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY; + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RELATEDCOLUMN), PROPERTY_ID_RELATEDCOLUMN, nAttrib,&m_ReferencedColumn, ::cppu::UnoType<OUString>::get()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VTable.cxx b/connectivity/source/sdbcx/VTable.cxx new file mode 100644 index 000000000..90c742782 --- /dev/null +++ b/connectivity/source/sdbcx/VTable.cxx @@ -0,0 +1,304 @@ +/* -*- 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/sdbcx/VTable.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/sequence.hxx> +#include <connectivity/sdbcx/VCollection.hxx> +#include <TConnection.hxx> +#include <connectivity/dbtools.hxx> +#include <connectivity/dbexception.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace ::connectivity; +using namespace ::connectivity::sdbcx; +using namespace ::dbtools; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + + +OUString SAL_CALL OTable::getImplementationName( ) +{ + if(isNew()) + return "com.sun.star.sdbcx.VTableDescriptor"; + return "com.sun.star.sdbcx.Table"; +} + + +css::uno::Sequence< OUString > SAL_CALL OTable::getSupportedServiceNames( ) +{ + return { isNew()?OUString("com.sun.star.sdbcx.TableDescriptor"):OUString("com.sun.star.sdbcx.Table") }; +} + +sal_Bool SAL_CALL OTable::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +OTable::OTable(OCollection* _pTables, + bool _bCase) + : OTableDescriptor_BASE(m_aMutex) + ,ODescriptor(OTableDescriptor_BASE::rBHelper,_bCase,true) + ,m_pTables(_pTables) +{ +} + +OTable::OTable( OCollection* _pTables, + bool _bCase, + const OUString& Name, const OUString& Type, + const OUString& Description,const OUString& SchemaName, + const OUString& CatalogName) : OTableDescriptor_BASE(m_aMutex) + ,ODescriptor(OTableDescriptor_BASE::rBHelper,_bCase) + ,m_CatalogName(CatalogName) + ,m_SchemaName(SchemaName) + ,m_Description(Description) + ,m_Type(Type) + ,m_pTables(_pTables) +{ + m_Name = Name; +} + +OTable::~OTable() +{ +} + +void OTable::construct() +{ + ODescriptor::construct(); + + sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY; + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME,nAttrib,&m_CatalogName, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib,&m_SchemaName, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DESCRIPTION), PROPERTY_ID_DESCRIPTION,nAttrib,&m_Description, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE), PROPERTY_ID_TYPE, nAttrib,&m_Type, ::cppu::UnoType<OUString>::get()); +} + +void SAL_CALL OTable::acquire() throw() +{ + OTableDescriptor_BASE::acquire(); +} + +void SAL_CALL OTable::release() throw() +{ + OTableDescriptor_BASE::release(); +} + + +Any SAL_CALL OTable::queryInterface( const Type & rType ) +{ + Any aRet = ODescriptor::queryInterface( rType); + if(!aRet.hasValue()) + { + if(!isNew()) + aRet = OTable_BASE::queryInterface( rType); + if(isNew() && (rType == cppu::UnoType<XIndexesSupplier>::get())) + return Any(); + if(!aRet.hasValue()) + aRet = OTableDescriptor_BASE::queryInterface( rType); + } + return aRet; +} + +Sequence< Type > SAL_CALL OTable::getTypes( ) +{ + if(isNew()) + return ::comphelper::concatSequences(ODescriptor::getTypes(),OTableDescriptor_BASE::getTypes()); + return ::comphelper::concatSequences(ODescriptor::getTypes(),OTableDescriptor_BASE::getTypes(),OTable_BASE::getTypes()); +} + +void SAL_CALL OTable::disposing() +{ + ODescriptor::disposing(); + + ::osl::MutexGuard aGuard(m_aMutex); + + if(m_xKeys) + m_xKeys->disposing(); + if(m_xColumns) + m_xColumns->disposing(); + if(m_xIndexes) + m_xIndexes->disposing(); + + m_pTables = nullptr; +} + +// XColumnsSupplier +Reference< XNameAccess > SAL_CALL OTable::getColumns( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed); + + try + { + if ( !m_xColumns ) + refreshColumns(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_xColumns.get(); +} + + +// XKeysSupplier +Reference< XIndexAccess > SAL_CALL OTable::getKeys( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed); + + Reference< XIndexAccess > xKeys; + + try + { + if ( !m_xKeys ) + refreshKeys(); + xKeys = m_xKeys.get(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return xKeys; +} + +cppu::IPropertyArrayHelper* OTable::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +cppu::IPropertyArrayHelper & OTable::getInfoHelper() +{ + return *getArrayHelper(isNew() ? 1 : 0); +} + +Reference< XPropertySet > SAL_CALL OTable::createDataDescriptor( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed); + + OTable* pTable = new OTable(m_pTables,isCaseSensitive(),m_Name,m_Type,m_Description,m_SchemaName,m_CatalogName); + pTable->setNew(true); + return pTable; +} + +// XIndexesSupplier +Reference< XNameAccess > SAL_CALL OTable::getIndexes( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed); + + try + { + if ( !m_xIndexes ) + refreshIndexes(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_xIndexes.get(); +} + +// XRename +void SAL_CALL OTable::rename( const OUString& newName ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed); + + const OUString sOldComposedName = getName(); + const Reference< XDatabaseMetaData> xMetaData = getMetaData(); + if ( xMetaData.is() ) + ::dbtools::qualifiedNameComponents(xMetaData,newName,m_CatalogName,m_SchemaName,m_Name,::dbtools::EComposeRule::InDataManipulation); + else + m_Name = newName; + + m_pTables->renameObject(sOldComposedName,newName); +} + +Reference< XDatabaseMetaData> OTable::getMetaData() const +{ + return nullptr; +} + +// XAlterTable +void SAL_CALL OTable::alterColumnByName( const OUString& /*colName*/, const Reference< XPropertySet >& /*descriptor*/ ) +{ + throwFeatureNotImplementedSQLException( "XAlterTable::alterColumnByName", *this ); +} + +void SAL_CALL OTable::alterColumnByIndex( sal_Int32 /*index*/, const Reference< XPropertySet >& /*descriptor*/ ) +{ + throwFeatureNotImplementedSQLException( "XAlterTable::alterColumnByIndex", *this ); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OTable::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +OUString SAL_CALL OTable::getName() +{ + // this is only correct for tables who haven't a schema or catalog name + OSL_ENSURE(m_CatalogName.isEmpty(),"getName(): forgot to override getName()!"); + OSL_ENSURE(m_SchemaName.isEmpty(),"getName(): forgot to override getName()!"); + return m_Name; +} + +void SAL_CALL OTable::setName( const OUString& /*aName*/ ) +{ +} + +void OTable::refreshColumns() +{ +} + +void OTable::refreshKeys() +{ +} + +void OTable::refreshIndexes() +{ +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VUser.cxx b/connectivity/source/sdbcx/VUser.cxx new file mode 100644 index 000000000..9cecd7dfd --- /dev/null +++ b/connectivity/source/sdbcx/VUser.cxx @@ -0,0 +1,180 @@ +/* -*- 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 <sdbcx/VUser.hxx> +#include <connectivity/sdbcx/VCollection.hxx> +#include <connectivity/dbexception.hxx> +#include <comphelper/sequence.hxx> + + +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +IMPLEMENT_SERVICE_INFO(OUser,"com.sun.star.sdbcx.VUser","com.sun.star.sdbcx.User"); + +OUser::OUser(bool _bCase) : OUser_BASE(m_aMutex) + , ODescriptor(OUser_BASE::rBHelper,_bCase,true) +{ +} + +OUser::OUser(const OUString& Name, bool _bCase) : OUser_BASE(m_aMutex) + ,ODescriptor(OUser_BASE::rBHelper,_bCase) +{ + m_Name = Name; +} + +OUser::~OUser( ) +{ +} + +void OUser::disposing() +{ + OPropertySetHelper::disposing(); + ::osl::MutexGuard aGuard(m_aMutex); + if(m_pGroups) + m_pGroups->disposing(); +} + +Any SAL_CALL OUser::queryInterface( const Type & rType ) +{ + Any aRet = ODescriptor::queryInterface( rType); + return aRet.hasValue() ? aRet : OUser_BASE::queryInterface( rType); +} + +Sequence< Type > SAL_CALL OUser::getTypes( ) +{ + return ::comphelper::concatSequences(ODescriptor::getTypes(),OUser_BASE::getTypes()); +} + +::cppu::IPropertyArrayHelper* OUser::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + +} + +::cppu::IPropertyArrayHelper & OUser::getInfoHelper() +{ + return *getArrayHelper(); +} + +// XUser +void SAL_CALL OUser::changePassword( const OUString& /*objPassword*/, const OUString& /*newPassword*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "XUser::changePassword", *this ); +} + +// XGroupsSupplier +Reference< XNameAccess > SAL_CALL OUser::getGroups( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE::rBHelper.bDisposed); + + try + { + if ( !m_pGroups ) + refreshGroups(); + } + catch( const RuntimeException& ) + { + // allowed to leave this method + throw; + } + catch( const Exception& ) + { + // allowed + } + + return m_pGroups.get(); +} + + +SAL_WNOUNREACHABLE_CODE_PUSH + +sal_Int32 SAL_CALL OUser::getPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::changePassword", *this ); + return 0; +} + +sal_Int32 SAL_CALL OUser::getGrantablePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::getGrantablePrivileges", *this ); + return 0; +} + +SAL_WNOUNREACHABLE_CODE_POP + + +void SAL_CALL OUser::grantPrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::grantPrivileges", *this ); +} + +void SAL_CALL OUser::revokePrivileges( const OUString& /*objName*/, sal_Int32 /*objType*/, sal_Int32 /*objPrivileges*/ ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(OUser_BASE::rBHelper.bDisposed); + ::dbtools::throwFeatureNotImplementedSQLException( "XAuthorizable::revokePrivileges", *this ); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OUser::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +OUString SAL_CALL OUser::getName( ) +{ + return m_Name; +} + +void SAL_CALL OUser::setName( const OUString& /*aName*/ ) +{ + OSL_FAIL( "OUser::setName: not implemented!" ); + // not allowed to throw an SQLException here ... +} + +// XInterface +void SAL_CALL OUser::acquire() throw() +{ + OUser_BASE::acquire(); +} + +void SAL_CALL OUser::release() throw() +{ + OUser_BASE::release(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/sdbcx/VView.cxx b/connectivity/source/sdbcx/VView.cxx new file mode 100644 index 000000000..317e985b5 --- /dev/null +++ b/connectivity/source/sdbcx/VView.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 <connectivity/sdbcx/VView.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/sequence.hxx> +#include <connectivity/dbtools.hxx> +#include <TConnection.hxx> + + +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; + +IMPLEMENT_SERVICE_INFO(OView,"com.sun.star.sdbcx.VView","com.sun.star.sdbcx.View"); + +OView::OView(bool _bCase, + const OUString& Name, + const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _xMetaData, + const OUString& Command, + const OUString& SchemaName, + const OUString& CatalogName) : ODescriptor(::comphelper::OMutexAndBroadcastHelper::m_aBHelper,_bCase) + ,m_CatalogName(CatalogName) + ,m_SchemaName(SchemaName) + ,m_Command(Command) + ,m_CheckOption(0) + ,m_xMetaData(_xMetaData) + +{ + m_Name = Name; + construct(); +} + +OView::OView(bool _bCase, const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _xMetaData) + : ODescriptor(::comphelper::OMutexAndBroadcastHelper::m_aBHelper, _bCase, true) + ,m_xMetaData(_xMetaData) +{ + construct(); +} + +OView::~OView() +{ +} + +void OView::construct() +{ + ODescriptor::construct(); + + sal_Int32 nAttrib = isNew() ? 0 : PropertyAttribute::READONLY; + + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CATALOGNAME), PROPERTY_ID_CATALOGNAME,nAttrib,&m_CatalogName, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCHEMANAME), PROPERTY_ID_SCHEMANAME, nAttrib,&m_SchemaName, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_COMMAND), PROPERTY_ID_COMMAND, nAttrib,&m_Command, ::cppu::UnoType<OUString>::get()); + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CHECKOPTION), PROPERTY_ID_CHECKOPTION,nAttrib,&m_CheckOption, ::cppu::UnoType<sal_Int32>::get()); +} + +Sequence< Type > SAL_CALL OView::getTypes( ) +{ + return ::comphelper::concatSequences(ODescriptor::getTypes(),OView_BASE::getTypes()); +} + +Any SAL_CALL OView::queryInterface( const Type & rType ) +{ + Any aRet = OView_BASE::queryInterface( rType); + return aRet.hasValue() ? aRet : ODescriptor::queryInterface( rType); +} + +::cppu::IPropertyArrayHelper* OView::createArrayHelper( sal_Int32 /*_nId*/ ) const +{ + return doCreateArrayHelper(); +} + +::cppu::IPropertyArrayHelper & OView::getInfoHelper() +{ + return *getArrayHelper(isNew() ? 1 : 0); +} + +OUString SAL_CALL OView::getName() +{ + OUString sComposedName; + if(m_xMetaData.is()) + sComposedName = ::dbtools::composeTableName( m_xMetaData, m_CatalogName, m_SchemaName, m_Name, false, ::dbtools::EComposeRule::InDataManipulation ); + else + { + Any aValue; + getFastPropertyValue(aValue,PROPERTY_ID_NAME); + aValue >>= sComposedName; + } + return sComposedName; +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OView::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + +void SAL_CALL OView::setName( const OUString& ) +{ +} + +void SAL_CALL OView::acquire() throw() +{ + OView_BASE::acquire(); +} + +void SAL_CALL OView::release() throw() +{ + OView_BASE::release(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |