diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /connectivity/source/drivers/mork/MQueryHelper.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream/1%7.0.4.tar.xz libreoffice-upstream/1%7.0.4.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'connectivity/source/drivers/mork/MQueryHelper.cxx')
-rw-r--r-- | connectivity/source/drivers/mork/MQueryHelper.cxx | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/connectivity/source/drivers/mork/MQueryHelper.cxx b/connectivity/source/drivers/mork/MQueryHelper.cxx new file mode 100644 index 000000000..aaf8cac6a --- /dev/null +++ b/connectivity/source/drivers/mork/MQueryHelper.cxx @@ -0,0 +1,321 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "MColumnAlias.hxx" +#include "MQueryHelper.hxx" +#include "MConnection.hxx" + +#include "MorkParser.hxx" +#include <string> +#include <vector> +#include <algorithm> + +#include <strings.hrc> + +#include <unotools/textsearch.hxx> +#include <sal/log.hxx> + +using namespace connectivity::mork; +using namespace connectivity; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; + + +static +std::vector<bool> entryMatchedByExpression(MQueryHelper* _aQuery, MQueryExpression const * _aExpr, MQueryHelperResultEntry* entry); + +MQueryHelperResultEntry::MQueryHelperResultEntry() +{ +} + +MQueryHelperResultEntry::~MQueryHelperResultEntry() +{ +} + +OUString MQueryHelperResultEntry::getValue( const OString &key ) const +{ + FieldMap::const_iterator iter = m_Fields.find( key ); + if ( iter == m_Fields.end() ) + { + return OUString(); + } + else + { + return iter->second; + } +} + +void MQueryHelperResultEntry::setValue( const OString &key, const OUString & rValue) +{ + m_Fields[ key ] = rValue; +} + +MQueryHelper::MQueryHelper(const OColumnAlias& _ca) + :m_rColumnAlias( _ca ) + ,m_aError() +{ + m_aResults.clear(); +} + +MQueryHelper::~MQueryHelper() +{ + clear_results(); +} + + +void MQueryHelper::setAddressbook(OUString const &ab) +{ + ::osl::MutexGuard aGuard(m_aMutex); + m_aAddressbook = ab; +} + +void MQueryHelper::append(std::unique_ptr<MQueryHelperResultEntry> resEnt) +{ + assert(resEnt); + m_aResults.push_back( std::move(resEnt) ); +} + +void MQueryHelper::clear_results() +{ + m_aResults.clear(); +} + +void MQueryHelper::reset() +{ + clear_results(); + m_aError.reset(); +} + +MQueryHelperResultEntry* +MQueryHelper::getByIndex(sal_uInt32 nRow) +{ + // Row numbers are from 1 to N, need to ensure this, and then + // subtract 1 + if ( nRow < 1 ) { + return nullptr; + } + return m_aResults[nRow -1].get(); +} + +sal_Int32 MQueryHelper::getResultCount() const +{ + sal_Int32 result = static_cast<sal_Int32>(m_aResults.size()); + + return result; +} + +bool MQueryHelper::getRowValue( ORowSetValue& rValue, sal_Int32 nDBRow,const OUString& aDBColumnName, sal_Int32 nType ) +{ + MQueryHelperResultEntry* pResEntry = getByIndex( nDBRow ); + + OSL_ENSURE( pResEntry != nullptr, "xResEntry == NULL"); + if (pResEntry == nullptr ) + { + rValue.setNull(); + return false; + } + switch ( nType ) + { + case DataType::VARCHAR: + rValue = pResEntry->getValue( m_rColumnAlias.getProgrammaticNameOrFallbackToUTF8Alias( aDBColumnName ) ); + break; + + default: + rValue.setNull(); + break; + } + + return true; +} + +sal_Int32 MQueryHelper::executeQuery(OConnection* xConnection, MQueryExpression & expr) +{ + reset(); + + OString oStringTable = OUStringToOString( m_aAddressbook, RTL_TEXTENCODING_UTF8 ); + std::set<int> listRecords; + bool handleListTable = false; + MorkParser* pMork; + + // check if we are retrieving the default table + if (oStringTable == "AddressBook" || oStringTable == "CollectedAddressBook") + { + pMork = xConnection->getMorkParser(oStringTable); + } + else + { + // Let's try to retrieve the list in Collected Addresses book + pMork = xConnection->getMorkParser("CollectedAddressBook"); + if (std::find(pMork->lists_.begin(), pMork->lists_.end(), m_aAddressbook) == pMork->lists_.end()) + { + // so the list is in Address book + // TODO : manage case where an address book has been created + pMork = xConnection->getMorkParser("AddressBook"); + } + handleListTable = true; + // retrieve row ids for that list table + std::string listTable = oStringTable.getStr(); + pMork->getRecordKeysForListTable(listTable, listRecords); + } + + MorkTableMap *Tables = pMork->getTables( 0x80 ); + if (!Tables) + return -1; + + MorkRowMap *Rows = nullptr; + + // Iterate all tables + for (auto & table : Tables->map) + { + if (table.first != 1) break; + Rows = MorkParser::getRows( 0x80, &table.second ); + if ( Rows ) + { + // Iterate all rows + for (auto const& row : Rows->map) + { + // list specific table + // only retrieve rowIds that belong to that list table. + if (handleListTable) + { + int rowId = row.first; + // belongs this row id to the list table? + if (listRecords.end() == listRecords.find(rowId)) + { + // no, skip it + continue; + } + } + + std::unique_ptr<MQueryHelperResultEntry> entry(new MQueryHelperResultEntry()); + for (auto const& cell : row.second) + { + std::string column = pMork->getColumn(cell.first); + std::string value = pMork->getValue(cell.second); + OString key(column.c_str(), static_cast<sal_Int32>(column.size())); + OString valueOString(value.c_str(), static_cast<sal_Int32>(value.size())); + OUString valueOUString = OStringToOUString( valueOString, RTL_TEXTENCODING_UTF8 ); + entry->setValue(key, valueOUString); + } + bool result = true; + for (bool elem : entryMatchedByExpression(this, &expr, entry.get())) + { + result = result && elem; + } + if (result) + { + append(std::move(entry)); + } + } + } + } + return 0; +} + +std::vector<bool> entryMatchedByExpression(MQueryHelper* _aQuery, MQueryExpression const * _aExpr, MQueryHelperResultEntry* entry) +{ + std::vector<bool> resultVector; + for (auto const& expr : _aExpr->getExpressions()) + { + if ( expr->isStringExpr() ) { + MQueryExpressionString* evStr = static_cast<MQueryExpressionString*> (expr); + // Set the 'name' property of the boolString. + OString attrName = _aQuery->getColumnAlias().getProgrammaticNameOrFallbackToUTF8Alias( evStr->getName() ); + SAL_INFO("connectivity.mork", "Name = " << attrName); + bool bRequiresValue = true; + OUString currentValue = entry->getValue(attrName); + if (evStr->getCond() == MQueryOp::Exists || evStr->getCond() == MQueryOp::DoesNotExist) + { + bRequiresValue = false; + } + if (bRequiresValue) + { + SAL_INFO("connectivity.mork", "Value = " << evStr->getValue() ); + const OUString& searchedValue = evStr->getValue(); + if (evStr->getCond() == MQueryOp::Is) { + SAL_INFO("connectivity.mork", "MQueryOp::Is; done"); + resultVector.push_back(currentValue == searchedValue); + } else if (evStr->getCond() == MQueryOp::IsNot) { + SAL_INFO("connectivity.mork", "MQueryOp::IsNot; done"); + resultVector.push_back(currentValue != searchedValue); + } else if (evStr->getCond() == MQueryOp::EndsWith) { + SAL_INFO("connectivity.mork", "MQueryOp::EndsWith; done"); + resultVector.push_back(currentValue.endsWith(searchedValue)); + } else if (evStr->getCond() == MQueryOp::BeginsWith) { + SAL_INFO("connectivity.mork", "MQueryOp::BeginsWith; done"); + resultVector.push_back(currentValue.startsWith(searchedValue)); + } else if (evStr->getCond() == MQueryOp::Contains) { + SAL_INFO("connectivity.mork", "MQueryOp::Contains; done"); + resultVector.push_back(currentValue.indexOf(searchedValue) != -1); + } else if (evStr->getCond() == MQueryOp::DoesNotContain) { + SAL_INFO("connectivity.mork", "MQueryOp::DoesNotContain; done"); + resultVector.push_back(currentValue.indexOf(searchedValue) == -1); + } else if (evStr->getCond() == MQueryOp::RegExp) { + SAL_INFO("connectivity.mork", "MQueryOp::RegExp; done"); + utl::SearchParam param( + searchedValue, utl::SearchParam::SearchType::Regexp); + utl::TextSearch ts(param, LANGUAGE_DONTKNOW); + sal_Int32 start = 0; + sal_Int32 end = currentValue.getLength(); + resultVector.push_back( + ts.SearchForward(currentValue, &start, &end)); + } + } else if (evStr->getCond() == MQueryOp::Exists) { + SAL_INFO("connectivity.mork", "MQueryOp::Exists; done"); + resultVector.push_back(!currentValue.isEmpty()); + } else if (evStr->getCond() == MQueryOp::DoesNotExist) { + SAL_INFO("connectivity.mork", "MQueryOp::DoesNotExist; done"); + resultVector.push_back(currentValue.isEmpty()); + } + } + else if ( expr->isExpr() ) { + SAL_INFO("connectivity.mork", "Appending Subquery Expression"); + MQueryExpression* queryExpression = static_cast<MQueryExpression*> (expr); + // recursive call + std::vector<bool> subquery_result = entryMatchedByExpression(_aQuery, queryExpression, entry); + MQueryExpression::bool_cond condition = queryExpression->getExpressionCondition(); + if (condition == MQueryExpression::OR) { + bool result = false; + for (bool elem : subquery_result) + { + result = result || elem; + } + resultVector.push_back(result); + } else { + assert(condition == MQueryExpression::AND && "only OR or AND should exist"); + bool result = true; + for (bool elem : subquery_result) + { + result = result && elem; + } + resultVector.push_back(result); + } + } + else { + // Should never see this... + SAL_WARN("connectivity.mork", "Unknown Expression Type!"); + _aQuery->getError().setResId(STR_ERROR_GET_ROW); + return resultVector; + } + } + return resultVector; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |