diff options
Diffstat (limited to '')
38 files changed, 8825 insertions, 0 deletions
diff --git a/connectivity/source/drivers/macab/MacabAddressBook.cxx b/connectivity/source/drivers/macab/MacabAddressBook.cxx new file mode 100644 index 000000000..02d4faf74 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabAddressBook.cxx @@ -0,0 +1,249 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "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) +{ + if(m_aAddressBook == nullptr) + { + // TODO: tell the user to reset the permission via "tccutil reset AddressBook" + // or the system preferences and try again, this time granting the access + throw RuntimeException( + "failed to access the macOS address book - permission not granted?" ); + } +} + + +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(std::u16string_view _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(std::u16string_view _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..a23e0c1eb --- /dev/null +++ b/connectivity/source/drivers/macab/MacabAddressBook.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 . + */ + +#pragma once + +#include "MacabRecords.hxx" +#include "MacabGroup.hxx" + +#include <string_view> +#include <vector> + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> + +namespace connectivity::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(std::u16string_view _groupName); + MacabRecords *getMacabRecords(std::u16string_view _tableName); + + MacabGroup *getMacabGroupMatch(const OUString& _groupName); + MacabRecords *getMacabRecordsMatch(const OUString& _tableName); + }; + +} + +/* 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..1757bb908 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabCatalog.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 . + */ + +#pragma once + +#include <sdbcx/VCatalog.hxx> + +namespace connectivity::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; + }; +} + +/* 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..6a49ad1d0 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabColumns.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 "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) + { + xRet = 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); + 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..7123af89d --- /dev/null +++ b/connectivity/source/drivers/macab/MacabColumns.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 "MacabTable.hxx" +#include <connectivity/sdbcx/VCollection.hxx> + +namespace connectivity::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); + }; +} + +/* 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..eaa6cf523 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabConnection.cxx @@ -0,0 +1,316 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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> +#include <cppuhelper/weak.hxx> + +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()) + { + xTab = new MacabCatalog(this); + m_xCatalog = xTab; + } + return xTab; +} + +MacabAddressBook* MacabConnection::getAddressBook() const +{ + return m_pAddressBook; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* createMacabConnection( void* _pDriver ) +{ + // by definition, the pointer crossing library boundaries as void ptr is acquired once + return cppu::acquire(new MacabConnection( static_cast< MacabDriver* >( _pDriver ) )); +} + +/* 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..dc2bfa34f --- /dev/null +++ b/connectivity/source/drivers/macab/MacabConnection.hxx @@ -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 . + */ + +#pragma once + +#include <connectivity/CommonTools.hxx> +#include <com/sun/star/lang/XServiceInfo.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::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; + }; +} + +/* 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..b54b844c9 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabDatabaseMetaData.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 "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/SQLException.hpp> +#include <com/sun/star/sdbc/TransactionIsolation.hpp> +#include <rtl/ref.hxx> + +#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; +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTableTypes( ) +{ + rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTableTypes); + + static ODatabaseMetaDataResultSet::ORows aRows = [] + { + static constexpr OUStringLiteral aTable = u"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(std::vector(aRows)); + return pResult; +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTypeInfo( ) +{ + rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::eTypeInfo); + + 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(std::vector(aRows)); + return pResult; +} + +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) +{ + rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns); + 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(std::move(aRows)); + return pResult; +} + +Reference< XResultSet > SAL_CALL MacabDatabaseMetaData::getTables( + const Any&, + const OUString&, + const OUString&, + const Sequence< OUString >& types) +{ + rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTables); + + // 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 constexpr OUStringLiteral aTable = u"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 pResult; + + 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(std::vector(aRows)); + return pResult; +} + +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 ) +{ + rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eVersionColumns); + + 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(std::move(aRows)); + return pResult; +} + +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..662be1c01 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabDatabaseMetaData.hxx @@ -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 . + */ + +#pragma once + +#include "MacabConnection.hxx" +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> +#include <cppuhelper/implbase.hxx> + +namespace connectivity::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; + }; +} + +/* 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..4667c690a --- /dev/null +++ b/connectivity/source/drivers/macab/MacabDriver.cxx @@ -0,0 +1,310 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 <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(); +} + +OUString SAL_CALL MacabDriver::getImplementationName( ) +{ + return "com.sun.star.comp.sdbc.macab.Driver"; +} + +sal_Bool SAL_CALL MacabDriver::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > SAL_CALL MacabDriver::getSupportedServiceNames( ) +{ + // which service is supported + // for more information @see com.sun.star.sdbc.Driver + return { "com.sun.star.sdbc.Driver" }; +} + +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"; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +connectivity_MacabDriver_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new MacabDriver(context)); +} + +/* 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..d18f5e982 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabDriver.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 . + */ + +#pragma once + +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/lang/XServiceInfo.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::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: + css::uno::Reference< css::uno::XComponentContext > const & + getComponentContext() const { return m_xContext; } + + /** returns the path of our configuration settings + */ + static OUString impl_getConfigurationSettingsPath(); + + explicit MacabDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + protected: + + // 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(); + }; + +} + +/* 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..ddcd47b46 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabGroup.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 "MacabRecords.hxx" + +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> + + +namespace connectivity::macab +{ + class MacabGroup: public MacabRecords { + public: + MacabGroup(const ABAddressBookRef _addressBook, const MacabRecords *_allRecords, const ABGroupRef _xGroup); + }; +} + +/* 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..da270dd05 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabHeader.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 "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(std::u16string_view 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& 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..24b3fc7b0 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabHeader.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 . + */ + +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include "MacabRecord.hxx" + +namespace connectivity::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(std::u16string_view 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(); + void operator++ (); + bool operator!= (const sal_Int32 i) const; + bool operator== (const sal_Int32 i) const; + macabfield *operator* () const; + }; + }; +} + +/* 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..6d72345b6 --- /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].getString(); + + 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; + 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..6e649bf64 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabPreparedStatement.hxx @@ -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 . + */ + +#pragma once + +#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::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; + }; +} + +/* 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..5184eefc8 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabRecord.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 . + */ + +#pragma once + +#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::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); + + }; +} + +/* 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..17ee6585d --- /dev/null +++ b/connectivity/source/drivers/macab/MacabRecords.cxx @@ -0,0 +1,1160 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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, std::u16string_view _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(std::u16string_view _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& 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..8d0d5cf6f --- /dev/null +++ b/connectivity/source/drivers/macab/MacabRecords.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 . + */ + +#pragma once + +#include <sal/config.h> + +#include <string_view> +#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::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, std::u16string_view _columnName) const; + sal_Int32 getFieldNumber(std::u16string_view _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(); + void operator++ (); + bool operator!= (const sal_Int32 i) const; + bool operator== (const sal_Int32 i) const; + MacabRecord *operator* () const; + }; + + }; +} + +/* 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..4142fcb6c --- /dev/null +++ b/connectivity/source/drivers/macab/MacabResultSet.cxx @@ -0,0 +1,1094 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 <rtl/ref.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() +{ + rtl::Reference<MacabConnection> pConnection = static_cast< MacabConnection *>(m_xStatement->getConnection().get()); + + m_aMacabRecords = pConnection->getAddressBook()->getMacabRecords(m_sTableName); +} + +void MacabResultSet::someMacabRecords(const MacabCondition *pCondition) +{ + rtl::Reference<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() noexcept +{ + MacabResultSet_BASE::acquire(); +} + +void SAL_CALL MacabResultSet::release() noexcept +{ + 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; + 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; + 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,u"UID"); + if(uidField != nullptr) + { + if(uidField->type == kABStringProperty) + { + return Any(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,u"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 +{ + return new OPropertyArrayHelper + { + { + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, + cppu::UnoType<OUString>::get(), + PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), + PROPERTY_ID_ISBOOKMARKABLE, + cppu::UnoType<bool>::get(), + PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType<sal_Int32>::get(), + PropertyAttribute::READONLY + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType<sal_Int32>::get(), + PropertyAttribute::READONLY + } + } + }; +} + +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..306ef562d --- /dev/null +++ b/connectivity/source/drivers/macab/MacabResultSet.hxx @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 "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::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() noexcept override; + virtual void SAL_CALL release() noexcept 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; + }; +} + +/* 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..e08d92cfc --- /dev/null +++ b/connectivity/source/drivers/macab/MacabResultSetMetaData.cxx @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "MacabResultSetMetaData.hxx" +#include "MacabHeader.hxx" +#include "MacabRecords.hxx" +#include "MacabAddressBook.hxx" +#include "macabutilities.hxx" +#include <connectivity/dbexception.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 constexpr OUStringLiteral aName = u"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..b82088154 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabResultSetMetaData.hxx @@ -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 . + */ + +#pragma once + +#include "MacabConnection.hxx" +#include <connectivity/CommonTools.hxx> +#include <com/sun/star/sdbc/XResultSetMetaData.hpp> +#include <cppuhelper/implbase.hxx> +#include <rtl/ref.hxx> + +namespace connectivity::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 > () noexcept + { 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; + }; +} + +/* 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..95b922ce6 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabStatement.cxx @@ -0,0 +1,631 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 <rtl/ref.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::macab +{ + void impl_throwError(TranslateId 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 + rtl::Reference<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); + + rtl::Reference<MacabResultSet> pResult = new MacabResultSet(this); + 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.get()); // SELECT which columns ? + selectRecords(pResult.get()); // WHERE which condition ? + sortRecords(pResult.get()); // 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 pResult; +} + +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 Any(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 + return new ::cppu::OPropertyArrayHelper + { + { + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), + PROPERTY_ID_CURSORNAME, + cppu::UnoType<OUString>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING), + PROPERTY_ID_ESCAPEPROCESSING, + cppu::UnoType<bool>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), + PROPERTY_ID_FETCHDIRECTION, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), + PROPERTY_ID_FETCHSIZE, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), + PROPERTY_ID_MAXFIELDSIZE, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), + PROPERTY_ID_MAXROWS, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), + PROPERTY_ID_QUERYTIMEOUT, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), + PROPERTY_ID_RESULTSETCONCURRENCY, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), + PROPERTY_ID_RESULTSETTYPE, + cppu::UnoType<sal_Int32>::get(), + 0 + }, + { + ::connectivity::OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_USEBOOKMARKS), + PROPERTY_ID_USEBOOKMARKS, + cppu::UnoType<bool>::get(), + 0 + } + } + }; +} + +::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() noexcept +{ + MacabCommonStatement_BASE::acquire(); +} + +void SAL_CALL MacabCommonStatement::release() noexcept +{ + 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..700a895c0 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabStatement.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 . + */ + +#pragma once + +#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/sdbc/SQLWarning.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::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() noexcept override; + virtual void SAL_CALL acquire() noexcept 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(); + }; +} + +/* 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..1628cd297 --- /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.reset(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..897d589cc --- /dev/null +++ b/connectivity/source/drivers/macab/MacabTable.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 . + */ + +#pragma once + +#include "MacabConnection.hxx" +#include <connectivity/sdbcx/VTable.hxx> + +namespace connectivity::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; } + }; +} + +/* 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..e7149d264 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabTables.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 "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 + { + xRet = new MacabTable( + this, + static_cast<MacabCatalog&>(m_rParent).getConnection(), + aName, + xRow->getString(4), + xRow->getString(5), + ""); + } + } + ::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..0b0d841b7 --- /dev/null +++ b/connectivity/source/drivers/macab/MacabTables.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 . + */ + +#pragma once + +#include <connectivity/sdbcx/VCollection.hxx> +#include <com/sun/star/sdbc/XDatabaseMetaData.hpp> + +namespace connectivity::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; + }; +} + +/* 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..7cbc0d9c8 --- /dev/null +++ b/connectivity/source/drivers/macab/macab1.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@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.macab.Driver" + constructor="connectivity_MacabDriver_get_implementation"> + <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..41e087b2c --- /dev/null +++ b/connectivity/source/drivers/macab/macabcondition.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 "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, std::u16string_view 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, std::u16string_view 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, std::u16string_view 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, std::u16string_view sColumnName, const OUString &sMatchString) + : MacabConditionColumn(header, sColumnName), + m_sMatchString(sMatchString) +{ +} + +MacabConditionEqual::MacabConditionEqual(const MacabHeader *header, std::u16string_view 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, std::u16string_view 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, std::u16string_view 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..32e7b7071 --- /dev/null +++ b/connectivity/source/drivers/macab/macabcondition.hxx @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 <sal/config.h> + +#include <string_view> + +#include "MacabHeader.hxx" +#include "MacabRecord.hxx" + +#include <connectivity/dbexception.hxx> + +namespace connectivity::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, + std::u16string_view sColumnName); + virtual bool isAlwaysTrue() const override; + virtual bool isAlwaysFalse() const override; +}; + +class MacabConditionNull : public MacabConditionColumn +{ + public: + /// @throws css::sdbc::SQLException + MacabConditionNull( + const MacabHeader *header, + std::u16string_view sColumnName); + virtual bool eval(const MacabRecord *aRecord) const override; +}; + +class MacabConditionNotNull : public MacabConditionColumn +{ + public: + /// @throws css::sdbc::SQLException + MacabConditionNotNull( + const MacabHeader *header, + std::u16string_view 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, + std::u16string_view sColumnName, + const OUString &sMatchString); +}; + +class MacabConditionEqual : public MacabConditionCompare +{ + public: + /// @throws css::sdbc::SQLException + MacabConditionEqual( + const MacabHeader *header, + std::u16string_view 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, + std::u16string_view 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, + std::u16string_view 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; +}; + +} + +/* 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..133e5d599 --- /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, std::u16string_view 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..e5eb6c987 --- /dev/null +++ b/connectivity/source/drivers/macab/macaborder.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 . + */ + +#pragma once + +#include <rtl/ustring.hxx> +#include "MacabHeader.hxx" +#include "MacabRecord.hxx" + +#include <memory> +#include <string_view> +#include <vector> + +namespace connectivity::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, std::u16string_view 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; + }; +} + +/* 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..cfe46f37f --- /dev/null +++ b/connectivity/source/drivers/macab/macabutilities.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/util/DateTime.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <unotools/resmgr.hxx> + +#include <time.h> +#include <premac.h> +#include <Carbon/Carbon.h> +#include <AddressBook/ABAddressBookC.h> +#include <postmac.h> + +namespace connectivity::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(TranslateId pErrorId); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |