283 lines
8.6 KiB
C++
283 lines
8.6 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <dbase/DIndexIter.hxx>
|
|
#include <com/sun/star/sdb/SQLFilterOperator.hpp>
|
|
|
|
using namespace ::com::sun::star::sdb;
|
|
using namespace connectivity;
|
|
using namespace connectivity::dbase;
|
|
using namespace connectivity::file;
|
|
|
|
// OIndexIterator
|
|
|
|
OIndexIterator::~OIndexIterator() {}
|
|
|
|
sal_uInt32 OIndexIterator::First() { return Find(true); }
|
|
|
|
sal_uInt32 OIndexIterator::Next() { return Find(false); }
|
|
|
|
sal_uInt32 OIndexIterator::Find(bool bFirst)
|
|
{
|
|
sal_uInt32 nRes = NODE_NOTFOUND;
|
|
|
|
if (bFirst)
|
|
{
|
|
m_aRoot = m_xIndex->getRoot();
|
|
m_aCurLeaf.Clear();
|
|
}
|
|
|
|
if (!m_pOperator)
|
|
{
|
|
// Preparation, position on the smallest element
|
|
if (bFirst)
|
|
{
|
|
ONDXPage* pPage = m_aRoot;
|
|
while (pPage && !pPage->IsLeaf())
|
|
pPage = pPage->GetChild(m_xIndex.get());
|
|
|
|
m_aCurLeaf = pPage;
|
|
m_nCurNode = NODE_NOTFOUND;
|
|
}
|
|
ONDXKey* pKey = GetNextKey();
|
|
nRes = pKey ? pKey->GetRecord() : NODE_NOTFOUND;
|
|
}
|
|
else if (dynamic_cast<const OOp_ISNOTNULL*>(m_pOperator) != nullptr)
|
|
nRes = GetNotNull(bFirst);
|
|
else if (dynamic_cast<const OOp_ISNULL*>(m_pOperator) != nullptr)
|
|
nRes = GetNull(bFirst);
|
|
else if (dynamic_cast<const OOp_LIKE*>(m_pOperator) != nullptr)
|
|
nRes = GetLike(bFirst);
|
|
else if (dynamic_cast<const OOp_COMPARE*>(m_pOperator) != nullptr)
|
|
nRes = GetCompare(bFirst);
|
|
|
|
return nRes;
|
|
}
|
|
|
|
ONDXKey* OIndexIterator::GetFirstKey(ONDXPage* pPage, const OOperand& rKey)
|
|
{
|
|
// searches a given key
|
|
// Speciality: At the end of the algorithm
|
|
// the actual page and the position of the node which fulfil the
|
|
// '<='-condition are saved. this is considered for inserts.
|
|
// ONDXIndex* m_pIndex = GetNDXIndex();
|
|
OOp_COMPARE aTempOp(SQLFilterOperator::GREATER);
|
|
sal_uInt16 i = 0;
|
|
|
|
if (pPage->IsLeaf())
|
|
{
|
|
// in the leaf the actual operation is run, otherwise temp. (>)
|
|
while (i < pPage->Count() && !m_pOperator->operate(&((*pPage)[i]).GetKey(), &rKey))
|
|
i++;
|
|
}
|
|
else
|
|
while (i < pPage->Count() && !aTempOp.operate(&((*pPage)[i]).GetKey(), &rKey))
|
|
i++;
|
|
|
|
ONDXKey* pFoundKey = nullptr;
|
|
if (!pPage->IsLeaf())
|
|
{
|
|
// descend further
|
|
ONDXPagePtr aPage = (i == 0) ? pPage->GetChild(m_xIndex.get())
|
|
: ((*pPage)[i - 1]).GetChild(m_xIndex.get(), pPage);
|
|
pFoundKey = aPage.Is() ? GetFirstKey(aPage, rKey) : nullptr;
|
|
}
|
|
else if (i == pPage->Count())
|
|
{
|
|
pFoundKey = nullptr;
|
|
}
|
|
else
|
|
{
|
|
pFoundKey = &(*pPage)[i].GetKey();
|
|
if (!m_pOperator->operate(pFoundKey, &rKey))
|
|
pFoundKey = nullptr;
|
|
|
|
m_aCurLeaf = pPage;
|
|
m_nCurNode = pFoundKey ? i : sal_uInt16(i - 1);
|
|
}
|
|
return pFoundKey;
|
|
}
|
|
|
|
sal_uInt32 OIndexIterator::GetCompare(bool bFirst)
|
|
{
|
|
ONDXKey* pKey = nullptr;
|
|
sal_Int32 ePredicateType = dynamic_cast<file::OOp_COMPARE&>(*m_pOperator).getPredicateType();
|
|
|
|
if (bFirst)
|
|
{
|
|
// Preparation, position on the smallest element
|
|
ONDXPage* pPage = m_aRoot;
|
|
switch (ePredicateType)
|
|
{
|
|
case SQLFilterOperator::NOT_EQUAL:
|
|
case SQLFilterOperator::LESS:
|
|
case SQLFilterOperator::LESS_EQUAL:
|
|
while (pPage && !pPage->IsLeaf())
|
|
pPage = pPage->GetChild(m_xIndex.get());
|
|
|
|
m_aCurLeaf = pPage;
|
|
m_nCurNode = NODE_NOTFOUND;
|
|
}
|
|
|
|
switch (ePredicateType)
|
|
{
|
|
case SQLFilterOperator::NOT_EQUAL:
|
|
while ((pKey = GetNextKey()) != nullptr)
|
|
if (m_pOperator->operate(pKey, m_pOperand))
|
|
break;
|
|
break;
|
|
case SQLFilterOperator::LESS:
|
|
while ((pKey = GetNextKey()) != nullptr)
|
|
if (!pKey->getValue().isNull())
|
|
break;
|
|
break;
|
|
case SQLFilterOperator::LESS_EQUAL:
|
|
while ((pKey = GetNextKey()) != nullptr)
|
|
;
|
|
break;
|
|
case SQLFilterOperator::GREATER_EQUAL:
|
|
case SQLFilterOperator::EQUAL:
|
|
pKey = GetFirstKey(m_aRoot, *m_pOperand);
|
|
break;
|
|
case SQLFilterOperator::GREATER:
|
|
pKey = GetFirstKey(m_aRoot, *m_pOperand);
|
|
if (!pKey)
|
|
while ((pKey = GetNextKey()) != nullptr)
|
|
if (m_pOperator->operate(pKey, m_pOperand))
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (ePredicateType)
|
|
{
|
|
case SQLFilterOperator::NOT_EQUAL:
|
|
while ((pKey = GetNextKey()) != nullptr)
|
|
if (m_pOperator->operate(pKey, m_pOperand))
|
|
break;
|
|
break;
|
|
case SQLFilterOperator::LESS:
|
|
case SQLFilterOperator::LESS_EQUAL:
|
|
case SQLFilterOperator::EQUAL:
|
|
pKey = GetNextKey();
|
|
if (pKey == nullptr || !m_pOperator->operate(pKey, m_pOperand))
|
|
{
|
|
pKey = nullptr;
|
|
m_aCurLeaf.Clear();
|
|
}
|
|
break;
|
|
case SQLFilterOperator::GREATER_EQUAL:
|
|
case SQLFilterOperator::GREATER:
|
|
pKey = GetNextKey();
|
|
}
|
|
}
|
|
|
|
return pKey ? pKey->GetRecord() : NODE_NOTFOUND;
|
|
}
|
|
|
|
sal_uInt32 OIndexIterator::GetLike(bool bFirst)
|
|
{
|
|
if (bFirst)
|
|
{
|
|
ONDXPage* pPage = m_aRoot;
|
|
|
|
while (pPage && !pPage->IsLeaf())
|
|
pPage = pPage->GetChild(m_xIndex.get());
|
|
|
|
m_aCurLeaf = pPage;
|
|
m_nCurNode = NODE_NOTFOUND;
|
|
}
|
|
|
|
ONDXKey* pKey;
|
|
while ((pKey = GetNextKey()) != nullptr)
|
|
if (m_pOperator->operate(pKey, m_pOperand))
|
|
break;
|
|
return pKey ? pKey->GetRecord() : NODE_NOTFOUND;
|
|
}
|
|
|
|
sal_uInt32 OIndexIterator::GetNull(bool bFirst)
|
|
{
|
|
if (bFirst)
|
|
{
|
|
ONDXPage* pPage = m_aRoot;
|
|
while (pPage && !pPage->IsLeaf())
|
|
pPage = pPage->GetChild(m_xIndex.get());
|
|
|
|
m_aCurLeaf = pPage;
|
|
m_nCurNode = NODE_NOTFOUND;
|
|
}
|
|
|
|
ONDXKey* pKey = GetNextKey();
|
|
if (pKey == nullptr || !pKey->getValue().isNull())
|
|
{
|
|
pKey = nullptr;
|
|
m_aCurLeaf.Clear();
|
|
}
|
|
return pKey ? pKey->GetRecord() : NODE_NOTFOUND;
|
|
}
|
|
|
|
sal_uInt32 OIndexIterator::GetNotNull(bool bFirst)
|
|
{
|
|
ONDXKey* pKey;
|
|
if (bFirst)
|
|
{
|
|
// go through all NULL values first
|
|
for (sal_uInt32 nRec = GetNull(bFirst); nRec != NODE_NOTFOUND; nRec = GetNull(false))
|
|
;
|
|
pKey = m_aCurLeaf.Is() ? &(*m_aCurLeaf)[m_nCurNode].GetKey() : nullptr;
|
|
}
|
|
else
|
|
pKey = GetNextKey();
|
|
|
|
return pKey ? pKey->GetRecord() : NODE_NOTFOUND;
|
|
}
|
|
|
|
ONDXKey* OIndexIterator::GetNextKey()
|
|
{
|
|
if (m_aCurLeaf.Is() && ((++m_nCurNode) >= m_aCurLeaf->Count()))
|
|
{
|
|
ONDXPage* pPage = m_aCurLeaf;
|
|
// search next page
|
|
while (pPage)
|
|
{
|
|
ONDXPage* pParentPage = pPage->GetParent();
|
|
if (pParentPage)
|
|
{
|
|
sal_uInt16 nPos = pParentPage->Search(pPage);
|
|
if (nPos != pParentPage->Count() - 1)
|
|
{ // page found
|
|
pPage = (*pParentPage)[o3tl::sanitizing_inc(nPos)].GetChild(m_xIndex.get(),
|
|
pParentPage);
|
|
break;
|
|
}
|
|
}
|
|
pPage = pParentPage;
|
|
}
|
|
|
|
// now go on with leaf
|
|
while (pPage && !pPage->IsLeaf())
|
|
pPage = pPage->GetChild(m_xIndex.get());
|
|
|
|
m_aCurLeaf = pPage;
|
|
m_nCurNode = 0;
|
|
}
|
|
return m_aCurLeaf.Is() ? &(*m_aCurLeaf)[m_nCurNode].GetKey() : nullptr;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|