sc/source/core/tool/interpr3.cxx |   44 ++++++++++++++++++++++++++++-----------
 1 file changed, 32 insertions(+), 12 deletions(-)

New commits:
commit c8a033f0bbcc61feef3b42ea6a8833bcbc6ac552
Author:     Eike Rathke <er...@redhat.com>
AuthorDate: Fri Mar 3 13:39:03 2023 +0100
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Sat Mar 4 20:53:33 2023 +0000

    Resolves: tdf#153924 handle non-numeric and error values in rank array
    
    ... of LARGE()/SMALL() instead of yielding error value for all result
    elements.
    
    Fallout from
    
        commit e4c2d0bb57ab8ea8f5c400d103d01376b8140f22
        CommitDate: Fri Nov 30 22:14:17 2018 +0100
    
            i#32345 Support a matrix of rank argument for LARGE()/SMALL()
    
    that in ScInterpreter::GetTopNumberArray() required the entire
    rank array would have to be numeric, which with an empty cell or
    string it isn't.
    
    Change-Id: Ieaa1a68bb8f98614119550b1442665b6fbb4817a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148178
    Reviewed-by: Eike Rathke <er...@redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit 019e751c71dcb2d34c6fd8bb9dda267c6ba2b48e)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148217
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx
index d95510acd51c..c20d7e0327e1 100644
--- a/sc/source/core/tool/interpr3.cxx
+++ b/sc/source/core/tool/interpr3.cxx
@@ -3638,8 +3638,8 @@ void ScInterpreter::CalculateSmallLarge(bool bSmall)
         return;
 
     SCSIZE nCol = 0, nRow = 0;
-    auto aArray = GetTopNumberArray(nCol, nRow);
-    const auto nRankArraySize = aArray.size();
+    const auto aArray = GetTopNumberArray(nCol, nRow);
+    const size_t nRankArraySize = aArray.size();
     if (nRankArraySize == 0 || nGlobalError != FormulaError::NONE)
     {
         PushNoValue();
@@ -3667,7 +3667,12 @@ void ScInterpreter::CalculateSmallLarge(bool bSmall)
     {
         const SCSIZE k = aRankArray[0];
         if (k < 1 || nSize < k)
-            PushNoValue();
+        {
+            if (!std::isfinite(aArray[0]))
+                PushDouble(aArray[0]);  // propagates error
+            else
+                PushNoValue();
+        }
         else
         {
             vector<double>::iterator iPos = aSortArray.begin() + (bSmall ? k-1 
: nSize-k);
@@ -3699,15 +3704,19 @@ void ScInterpreter::CalculateSmallLarge(bool bSmall)
         else
             std::sort(aSortArray.begin(), aSortArray.end());
 
-        aArray.clear();
-        for (SCSIZE n : aRankArray)
+        std::vector<double> aResultArray;
+        aResultArray.reserve(nRankArraySize);
+        for (size_t i = 0; i < nRankArraySize; ++i)
         {
+            const SCSIZE n = aRankArray[i];
             if (1 <= n && n <= nSize)
-                aArray.push_back( aSortArray[bSmall ? n-1 : nSize-n]);
+                aResultArray.push_back( aSortArray[bSmall ? n-1 : nSize-n]);
+            else if (!std::isfinite( aArray[i]))
+                aResultArray.push_back( aArray[i]);  // propagate error
             else
-                aArray.push_back( CreateDoubleError( FormulaError::NoValue));
+                aResultArray.push_back( CreateDoubleError( 
FormulaError::IllegalArgument));
         }
-        ScMatrixRef pResult = GetNewMat(nCol, nRow, aArray);
+        ScMatrixRef pResult = GetNewMat(nCol, nRow, aResultArray);
         PushMatrix(pResult);
     }
 }
@@ -3912,19 +3921,30 @@ std::vector<double> ScInterpreter::GetTopNumberArray( 
SCSIZE& rCol, SCSIZE& rRow
             if (!pMat)
                 break;
 
+            const SCSIZE nCount = pMat->GetElementCount();
+            aArray.reserve(nCount);
+            // Do not propagate errors from matrix elements as global error.
+            pMat->SetErrorInterpreter(nullptr);
             if (pMat->IsNumeric())
             {
-                SCSIZE nCount = pMat->GetElementCount();
-                aArray.reserve(nCount);
                 for (SCSIZE i = 0; i < nCount; ++i)
                     aArray.push_back(pMat->GetDouble(i));
-                pMat->GetDimensions(rCol, rRow);
             }
             else
-                SetError(FormulaError::IllegalParameter);
+            {
+                for (SCSIZE i = 0; i < nCount; ++i)
+                {
+                    if (pMat->IsValue(i))
+                        aArray.push_back( pMat->GetDouble(i));
+                    else
+                        aArray.push_back( CreateDoubleError( 
FormulaError::NoValue));
+                }
+            }
+            pMat->GetDimensions(rCol, rRow);
         }
         break;
         default:
+            PopError();
             SetError(FormulaError::IllegalParameter);
         break;
     }

Reply via email to