Kaydet (Commit) ace16e50 authored tarafından Luboš Luňák's avatar Luboš Luňák

cache mdds access in ScTable::ValidQuery() (tdf#80853)

Once more, mdds always searches from the start of the container,
so iterating is quadratic.

Change-Id: I8f8f3b5aad5c3342a10c21df3ad2d0d3fcaea8ad
Reviewed-on: https://gerrit.libreoffice.org/72368
Tested-by: Jenkins
Reviewed-by: 's avatarLuboš Luňák <l.lunak@collabora.com>
üst 0d58f51d
...@@ -218,6 +218,8 @@ public: ...@@ -218,6 +218,8 @@ public:
bool bConsiderCellDrawObjects=false) const; bool bConsiderCellDrawObjects=false) const;
bool HasDataAt(sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow, bool bConsiderCellNotes=false, bool HasDataAt(sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow, bool bConsiderCellNotes=false,
bool bConsiderCellDrawObjects=false) const; bool bConsiderCellDrawObjects=false) const;
bool HasDataAt(sc::ColumnBlockPosition& rBlockPos, SCROW nRow, bool bConsiderCellNotes=false,
bool bConsiderCellDrawObjects=false);
bool HasVisibleDataAt(SCROW nRow) const; bool HasVisibleDataAt(SCROW nRow) const;
SCROW GetFirstDataPos() const; SCROW GetFirstDataPos() const;
SCROW GetLastDataPos() const; SCROW GetLastDataPos() const;
......
...@@ -64,6 +64,7 @@ class ColumnSpanSet; ...@@ -64,6 +64,7 @@ class ColumnSpanSet;
class RangeColumnSpanSet; class RangeColumnSpanSet;
class ColumnSet; class ColumnSet;
struct ColumnBlockPosition; struct ColumnBlockPosition;
class TableColumnBlockPositionSet;
struct RefUpdateContext; struct RefUpdateContext;
struct RefUpdateInsertTabContext; struct RefUpdateInsertTabContext;
struct RefUpdateDeleteTabContext; struct RefUpdateDeleteTabContext;
...@@ -930,7 +931,8 @@ public: ...@@ -930,7 +931,8 @@ public:
bool ValidQuery( bool ValidQuery(
SCROW nRow, const ScQueryParam& rQueryParam, const ScRefCellValue* pCell = nullptr, SCROW nRow, const ScQueryParam& rQueryParam, const ScRefCellValue* pCell = nullptr,
bool* pbTestEqualCondition = nullptr, const ScInterpreterContext* pContext = nullptr); bool* pbTestEqualCondition = nullptr, const ScInterpreterContext* pContext = nullptr,
sc::TableColumnBlockPositionSet* pBlockPos = nullptr );
void TopTenQuery( ScQueryParam& ); void TopTenQuery( ScQueryParam& );
SCSIZE Query(const ScQueryParam& rQueryParam, bool bKeepSub); SCSIZE Query(const ScQueryParam& rQueryParam, bool bKeepSub);
bool CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam); bool CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam);
......
...@@ -3100,6 +3100,22 @@ bool ScColumn::HasDataAt(sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow, ...@@ -3100,6 +3100,22 @@ bool ScColumn::HasDataAt(sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow,
return aPos.first->type != sc::element_type_empty; return aPos.first->type != sc::element_type_empty;
} }
bool ScColumn::HasDataAt(sc::ColumnBlockPosition& rBlockPos, SCROW nRow,
bool bConsiderCellNotes, bool bConsiderCellDrawObjects)
{
if (bConsiderCellNotes && !IsNotesEmptyBlock(nRow, nRow))
return true;
if (bConsiderCellDrawObjects && !IsDrawObjectsEmptyBlock(nRow, nRow))
return true;
std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
if (aPos.first == maCells.end())
return false;
rBlockPos.miCellPos = aPos.first; // Store this for next call.
return aPos.first->type != sc::element_type_empty;
}
bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
{ {
if (pAttrArray && rCol.pAttrArray) if (pAttrArray && rCol.pAttrArray)
......
...@@ -2729,7 +2729,7 @@ public: ...@@ -2729,7 +2729,7 @@ public:
bool ScTable::ValidQuery( bool ScTable::ValidQuery(
SCROW nRow, const ScQueryParam& rParam, const ScRefCellValue* pCell, bool* pbTestEqualCondition, SCROW nRow, const ScQueryParam& rParam, const ScRefCellValue* pCell, bool* pbTestEqualCondition,
const ScInterpreterContext* pContext) const ScInterpreterContext* pContext, sc::TableColumnBlockPositionSet* pBlockPos)
{ {
if (!rParam.GetEntry(0).bDoQuery) if (!rParam.GetEntry(0).bDoQuery)
return true; return true;
...@@ -2753,19 +2753,36 @@ bool ScTable::ValidQuery( ...@@ -2753,19 +2753,36 @@ bool ScTable::ValidQuery(
// We can only handle one single direct query passed as a known pCell, // We can only handle one single direct query passed as a known pCell,
// subsequent queries have to obtain the cell. // subsequent queries have to obtain the cell.
ScRefCellValue aCell( (pCell && it == itBeg) ? *pCell : GetCellValue(nCol, nRow)); ScRefCellValue aCell;
if(pCell && it == itBeg)
aCell = *pCell;
else if( pBlockPos )
{ // hinted mdds access
ScColumn* column = FetchColumn(nCol);
aCell = column->GetCellValue(*pBlockPos->getBlockPosition( nCol ), nRow);
}
else
aCell = GetCellValue(nCol, nRow);
std::pair<bool,bool> aRes(false, false); std::pair<bool,bool> aRes(false, false);
const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems(); const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
if (rItems.size() == 1 && rItems.front().meType == ScQueryEntry::ByEmpty) if (rItems.size() == 1 && rItems.front().meType == ScQueryEntry::ByEmpty)
{ {
bool hasData;
if( pBlockPos )
{
ScColumn* column = FetchColumn(rEntry.nField);
hasData = column->HasDataAt(*pBlockPos->getBlockPosition(rEntry.nField), nRow);
}
else
hasData = aCol[rEntry.nField].HasDataAt(nRow);
if (rEntry.IsQueryByEmpty()) if (rEntry.IsQueryByEmpty())
aRes.first = !aCol[rEntry.nField].HasDataAt(nRow); aRes.first = !hasData;
else else
{ {
assert(rEntry.IsQueryByNonEmpty()); assert(rEntry.IsQueryByNonEmpty());
aRes.first = aCol[rEntry.nField].HasDataAt(nRow); aRes.first = hasData;
} }
} }
else else
...@@ -3056,11 +3073,13 @@ SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub) ...@@ -3056,11 +3073,13 @@ SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub)
aParam.nDestCol, aParam.nDestRow, aParam.nDestTab ); aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
} }
sc::TableColumnBlockPositionSet blockPos( GetDoc(), nTab ); // cache mdds access
SCROW nRealRow2 = aParam.nRow2; SCROW nRealRow2 = aParam.nRow2;
for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j) for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j)
{ {
bool bResult; // Filter result bool bResult; // Filter result
bool bValid = ValidQuery(j, aParam); bool bValid = ValidQuery(j, aParam, nullptr, nullptr, nullptr, &blockPos);
if (!bValid && bKeepSub) // Keep subtotals if (!bValid && bKeepSub) // Keep subtotals
{ {
for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++) for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment