diff options
author | Eike Rathke <erack@redhat.com> | 2023-03-12 15:20:45 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2023-03-13 09:17:12 +0000 |
commit | 9820f754f1a8a26568d4d848072fe8bb5f6c04b1 (patch) | |
tree | 85a747933eae0a80f088eec68130f9755df99ccf /sc | |
parent | c5460594c21bab12db2d5a6601db84ea9726c416 (diff) |
Resolves: tdf#154125 Fix INDEX() one-dimensional vector access
For i62850 a (not documented by Excel in
https://support.microsoft.com/en-us/office/index-function-a5dcf0dd-996d-40a4-a822-b56b061328bd?ui=en-us&rs=en-us&ad=us)
one-dimensional vector's element access was implemented with
non-sufficient conditions that prevented returning an entire
vector. Later ODFF defined proper conditions for that, see
https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part4-formula/OpenDocument-v1.3-os-part4-formula.html#INDEX
Also, that vector element case assumed vector replication to the
other dimension as usual, which is not the case here, access to
the other dimension's index >1 must return error.
Change-Id: I604c2355f0aca2988cb13f0d4f54ccd2d74c3b0d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148736
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
(cherry picked from commit df706f47a2b62248d222911db12c674e6507e5c6)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148755
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 63 |
1 files changed, 51 insertions, 12 deletions
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 5673bb7ecda2..ac0fb22b6231 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -8674,10 +8674,17 @@ void ScInterpreter::ScIndex() nArea = GetUInt32(); else nArea = 1; + bool bColMissing; if (nParamCount >= 3) + { + bColMissing = IsMissing(); nCol = static_cast<SCCOL>(GetInt16()); + } else + { + bColMissing = false; nCol = 0; + } if (nParamCount >= 2) nRow = static_cast<SCROW>(GetInt32()); else @@ -8710,25 +8717,57 @@ void ScInterpreter::ScIndex() { SCSIZE nC, nR; pMat->GetDimensions(nC, nR); + // Access one element of a vector independent of col/row - // orientation? - bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1)); - SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol), - static_cast<SCSIZE>(nRow)); + // orientation. Excel documentation does not mention, but + // i62850 had a .xls example of a row vector accessed by + // row number returning one element. This + // INDEX(row_vector;element) behaves the same as + // INDEX(row_vector;0;element) and thus contradicts Excel + // documentation where the second parameter is always + // row_num. + // + // ODFF v1.3 in 6.14.6 INDEX states "If DataSource is a + // one-dimensional row vector, Row is optional, which + // effectively makes Row act as the column offset into the + // vector". Guess the first Row is a typo and should read + // Column instead. + + const bool bRowVectorSpecial = (nParamCount == 2 || bColMissing); + const bool bRowVectorElement = (nR == 1 && (nCol != 0 || (bRowVectorSpecial && nRow != 0))); + const bool bVectorElement = (bRowVectorElement || (nC == 1 && nRow != 0)); + if (nC == 0 || nR == 0 || - (!bVector && (o3tl::make_unsigned(nCol) > nC || - o3tl::make_unsigned(nRow) > nR)) || - (bVector && nElement > nC * nR)) + (!bVectorElement && (o3tl::make_unsigned(nCol) > nC || + o3tl::make_unsigned(nRow) > nR))) PushIllegalArgument(); else if (nCol == 0 && nRow == 0) sp = nOldSp; - else if (bVector) + else if (bVectorElement) { - --nElement; - if (pMat->IsStringOrEmpty( nElement)) - PushString( pMat->GetString(nElement).getString()); + // Vectors here don't replicate to the other dimension. + SCSIZE nElement, nOtherDimension; + if (bRowVectorElement && !bRowVectorSpecial) + { + nElement = o3tl::make_unsigned(nCol); + nOtherDimension = o3tl::make_unsigned(nRow); + } else - PushDouble( pMat->GetDouble( nElement)); + { + nElement = o3tl::make_unsigned(nRow); + nOtherDimension = o3tl::make_unsigned(nCol); + } + + if (nElement == 0 || nElement > nC * nR || nOtherDimension > 1) + PushIllegalArgument(); + else + { + --nElement; + if (pMat->IsStringOrEmpty( nElement)) + PushString( pMat->GetString(nElement).getString()); + else + PushDouble( pMat->GetDouble( nElement)); + } } else if (nCol == 0) { |