diff options
Diffstat (limited to 'sc/source/core/data')
-rw-r--r-- | sc/source/core/data/dociter.cxx | 62 | ||||
-rw-r--r-- | sc/source/core/data/table3.cxx | 42 |
2 files changed, 103 insertions, 1 deletions
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx index 3277d3692433..565565f00a11 100644 --- a/sc/source/core/data/dociter.cxx +++ b/sc/source/core/data/dociter.cxx @@ -1245,6 +1245,17 @@ bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol, SCROW& nFoundRow, bool bSearchForEqualAfterMismatch, bool bIgnoreMismatchOnLeadingStringsP ) { + // Set and automatically reset mpParam->mbRangeLookup when returning. We + // could use comphelper::FlagRestorationGuard, but really, that one is + // overengineered for this simple purpose here. + struct BoolResetter + { + bool& mr; + bool mb; + BoolResetter( bool& r, bool b ) : mr(r), mb(r) { r = b; } + ~BoolResetter() { mr = mb; } + } aRangeLookupResetter( mpParam->mbRangeLookup, true); + nFoundCol = MAXCOL+1; nFoundRow = MAXROW+1; SetStopOnMismatch( true ); // assume sorted keys @@ -1253,7 +1264,22 @@ bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol, bool bRegExp = mpParam->bRegExp && mpParam->GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByString; bool bBinary = !bRegExp && mpParam->bByRow && (mpParam->GetEntry(0).eOp == SC_LESS_EQUAL || mpParam->GetEntry(0).eOp == SC_GREATER_EQUAL); - if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst()) + bool bFound = false; + if (bBinary) + { + if (BinarySearch()) + { + // BinarySearch() already positions correctly and only needs real + // query comparisons afterwards, skip the verification check below. + mpParam->mbRangeLookup = false; + bFound = GetThis(); + } + } + else + { + bFound = GetFirst(); + } + if (bFound) { // First equal entry or last smaller than (greater than) entry. PositionType aPosSave; @@ -1272,9 +1298,43 @@ bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol, { // Step back to last in range and adjust position markers for // GetNumberFormat() or similar. + SCCOL nColDiff = nCol - nFoundCol; nCol = nFoundCol; nRow = nFoundRow; maCurPos = aPosSave; + if (mpParam->mbRangeLookup) + { + // Verify that the found entry does not only fulfill the range + // lookup but also the real query, i.e. not numeric was found + // if query is ByString and vice versa. + mpParam->mbRangeLookup = false; + // Step back the last field advance if GetNext() did one. + if (bAdvanceQuery && nColDiff) + { + SCSIZE nEntries = mpParam->GetEntryCount(); + for (SCSIZE j=0; j < nEntries; ++j) + { + ScQueryEntry& rEntry = mpParam->GetEntry( j ); + if (rEntry.bDoQuery) + { + if (rEntry.nField - nColDiff >= 0) + rEntry.nField -= nColDiff; + else + { + assert(!"FindEqualOrSortedLastInRange: rEntry.nField -= nColDiff < 0"); + } + } + else + break; // for + } + } + // Check it. + if (!GetThis()) + { + nFoundCol = MAXCOL+1; + nFoundRow = MAXROW+1; + } + } } } if ( IsEqualConditionFulfilled() ) diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index 05c43c3da09f..a92748568d2f 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -1513,6 +1513,41 @@ public: return std::pair<bool,bool>(bOk, bTestEqual); } + + // To be called only if both isQueryByValue() and isQueryByString() + // returned false and range lookup is wanted! In range lookup comparison + // numbers are less than strings. Nothing else is compared. + std::pair<bool,bool> compareByRangeLookup( + const ScRefCellValue& rCell, SCCOL nCol, SCROW nRow, + const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem) + { + bool bTestEqual = false; + + if (rItem.meType == ScQueryEntry::ByString && rEntry.eOp != SC_LESS && rEntry.eOp != SC_LESS_EQUAL) + return std::pair<bool,bool>(false, bTestEqual); + + if (rItem.meType != ScQueryEntry::ByString && rEntry.eOp != SC_GREATER && rEntry.eOp != SC_GREATER_EQUAL) + return std::pair<bool,bool>(false, bTestEqual); + + if (!rCell.isEmpty()) + { + if (rItem.meType == ScQueryEntry::ByString) + { + if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode()) + // Error values are compared as string. + return std::pair<bool,bool>(false, bTestEqual); + + return std::pair<bool,bool>(rCell.hasNumeric(), bTestEqual); + } + + return std::pair<bool,bool>(!rCell.hasNumeric(), bTestEqual); + } + + if (rItem.meType == ScQueryEntry::ByString) + return std::pair<bool,bool>(mrTab.HasValueData(nCol, nRow), bTestEqual); + + return std::pair<bool,bool>(!mrTab.HasValueData(nCol, nRow), bTestEqual); + } }; } @@ -1578,6 +1613,13 @@ bool ScTable::ValidQuery( aRes.first |= aThisRes.first; aRes.second |= aThisRes.second; } + else if (rParam.mbRangeLookup) + { + std::pair<bool,bool> aThisRes = + aEval.compareByRangeLookup(aCell, nCol, nRow, rEntry, *itr); + aRes.first |= aThisRes.first; + aRes.second |= aThisRes.second; + } if (aRes.first && aRes.second) break; |