tdf#128425 Add Excel2021 function XMATCH to Calc
https://issues.oasis-open.org/browse/OFFICE-4155 Change-Id: I7791ab873cf62ce882feba75dc0d722bc5990f9a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163260 Tested-by: Jenkins Reviewed-by: Balazs Varga <balazs.varga.extern@allotropia.de>
This commit is contained in:
@@ -266,6 +266,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF[] =
|
||||
{ "INDIRECT" , SC_OPCODE_INDIRECT },
|
||||
{ "ADDRESS" , SC_OPCODE_ADDRESS },
|
||||
{ "MATCH" , SC_OPCODE_MATCH },
|
||||
{ "COM.MICROSOFT.XMATCH" , SC_OPCODE_X_MATCH },
|
||||
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
|
||||
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
|
||||
{ "SUMIF" , SC_OPCODE_SUM_IF },
|
||||
@@ -714,6 +715,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML[] =
|
||||
{ "INDIRECT" , SC_OPCODE_INDIRECT },
|
||||
{ "ADDRESS" , SC_OPCODE_ADDRESS },
|
||||
{ "MATCH" , SC_OPCODE_MATCH },
|
||||
{ "_xlfn.XMATCH" , SC_OPCODE_X_MATCH },
|
||||
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
|
||||
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
|
||||
{ "SUMIF" , SC_OPCODE_SUM_IF },
|
||||
@@ -1165,6 +1167,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_PODF[] =
|
||||
{ "INDIRECT" , SC_OPCODE_INDIRECT },
|
||||
{ "ADDRESS" , SC_OPCODE_ADDRESS },
|
||||
{ "MATCH" , SC_OPCODE_MATCH },
|
||||
{ "XMATCH" , SC_OPCODE_X_MATCH },
|
||||
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
|
||||
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
|
||||
{ "SUMIF" , SC_OPCODE_SUM_IF },
|
||||
@@ -1617,6 +1620,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_API[] =
|
||||
{ "INDIRECT" , SC_OPCODE_INDIRECT },
|
||||
{ "ADDRESS" , SC_OPCODE_ADDRESS },
|
||||
{ "MATCH" , SC_OPCODE_MATCH },
|
||||
{ "XMATCH" , SC_OPCODE_X_MATCH },
|
||||
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
|
||||
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
|
||||
{ "SUMIF" , SC_OPCODE_SUM_IF },
|
||||
@@ -2067,6 +2071,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH[] =
|
||||
{ "INDIRECT" , SC_OPCODE_INDIRECT },
|
||||
{ "ADDRESS" , SC_OPCODE_ADDRESS },
|
||||
{ "MATCH" , SC_OPCODE_MATCH },
|
||||
{ "XMATCH" , SC_OPCODE_X_MATCH },
|
||||
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
|
||||
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
|
||||
{ "SUMIF" , SC_OPCODE_SUM_IF },
|
||||
@@ -2498,6 +2503,7 @@ const std::pair<TranslateId, int> RID_STRLIST_FUNCTION_NAMES[] =
|
||||
{ NC_("RID_STRLIST_FUNCTION_NAMES", "INDIRECT") , SC_OPCODE_INDIRECT },
|
||||
{ NC_("RID_STRLIST_FUNCTION_NAMES", "ADDRESS") , SC_OPCODE_ADDRESS },
|
||||
{ NC_("RID_STRLIST_FUNCTION_NAMES", "MATCH") , SC_OPCODE_MATCH },
|
||||
{ NC_("RID_STRLIST_FUNCTION_NAMES", "XMATCH") , SC_OPCODE_X_MATCH },
|
||||
{ NC_("RID_STRLIST_FUNCTION_NAMES", "COUNTBLANK") , SC_OPCODE_COUNT_EMPTY_CELLS },
|
||||
{ NC_("RID_STRLIST_FUNCTION_NAMES", "COUNTIF") , SC_OPCODE_COUNT_IF },
|
||||
{ NC_("RID_STRLIST_FUNCTION_NAMES", "SUMIF") , SC_OPCODE_SUM_IF },
|
||||
|
||||
@@ -399,7 +399,7 @@
|
||||
#define SC_OPCODE_ISPMT 386
|
||||
#define SC_OPCODE_HYPERLINK 387
|
||||
#define SC_OPCODE_X_LOOKUP 388
|
||||
// free: 389
|
||||
#define SC_OPCODE_X_MATCH 389
|
||||
#define SC_OPCODE_GET_PIVOT_DATA 390
|
||||
#define SC_OPCODE_EUROCONVERT 391
|
||||
#define SC_OPCODE_NUMBERVALUE 392
|
||||
|
||||
@@ -307,6 +307,7 @@ enum OpCode : sal_uInt16
|
||||
ocIndirect = SC_OPCODE_INDIRECT,
|
||||
ocAddress = SC_OPCODE_ADDRESS,
|
||||
ocMatch = SC_OPCODE_MATCH,
|
||||
ocXMatch = SC_OPCODE_X_MATCH,
|
||||
ocCountEmptyCells = SC_OPCODE_COUNT_EMPTY_CELLS,
|
||||
ocCountIf = SC_OPCODE_COUNT_IF,
|
||||
ocSumIf = SC_OPCODE_SUM_IF,
|
||||
@@ -790,6 +791,7 @@ inline std::string OpCodeEnumToString(OpCode eCode)
|
||||
case ocIndirect: return "Indirect";
|
||||
case ocAddress: return "Address";
|
||||
case ocMatch: return "Match";
|
||||
case ocXMatch: return "XMatch";
|
||||
case ocCountEmptyCells: return "CountEmptyCells";
|
||||
case ocCountIf: return "CountIf";
|
||||
case ocSumIf: return "SumIf";
|
||||
|
||||
@@ -74,6 +74,7 @@ https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part4-formula/OpenDocume
|
||||
* HLOOKUP
|
||||
* LOOKUP
|
||||
* MATCH
|
||||
* XMATCH
|
||||
* VLOOKUP
|
||||
* XLOOKUP
|
||||
* Mathematical Functions
|
||||
|
||||
@@ -594,5 +594,6 @@ inline constexpr OUString HID_FUNC_FOURIER = u"SC_HID_FUNC_FOURIER"_ustr;
|
||||
inline constexpr OUString HID_FUNC_RAND_NV = u"SC_HID_FUNC_RAND_NV"_ustr;
|
||||
inline constexpr OUString HID_FUNC_RANDBETWEEN_NV = u"SC_HID_FUNC_RANDBETWEEN_NV"_ustr;
|
||||
inline constexpr OUString HID_FUNC_XLOOKUP_MS = u"SC_HID_FUNC_XLOOKUP_MS"_ustr;
|
||||
inline constexpr OUString HID_FUNC_XMATCH_MS = u"SC_HID_FUNC_XMATCH_MS"_ustr;
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -3443,6 +3443,20 @@ const TranslateId SC_OPCODE_MATCH_ARY[] =
|
||||
NC_("SC_OPCODE_MATCH", "Type can take the value 1 (first column array ascending), 0 (exact match or wildcard or regular expression match) or -1 (first column array descending) and determines the criteria to be used for comparison purposes.")
|
||||
};
|
||||
|
||||
// -=*# Resource for function XMATCH #*=-
|
||||
const TranslateId SC_OPCODE_X_MATCH_ARY[] =
|
||||
{
|
||||
NC_("SC_OPCODE_X_MATCH", "Defines a relative position in an array or range of cells after comparing values."),
|
||||
NC_("SC_OPCODE_X_MATCH", "Search criterion"),
|
||||
NC_("SC_OPCODE_X_MATCH", "The value to be used for comparison."),
|
||||
NC_("SC_OPCODE_X_MATCH", "Search Array"),
|
||||
NC_("SC_OPCODE_X_MATCH", "The array or range to search."),
|
||||
NC_("SC_OPCODE_X_MATCH", "Match Mode"),
|
||||
NC_("SC_OPCODE_X_MATCH", "0, -1, 1 or 2 "), // TODO : add explanation of values
|
||||
NC_("SC_OPCODE_X_MATCH", "Search Mode"),
|
||||
NC_("SC_OPCODE_X_MATCH", "1, -1, 2 or -2 ") // TODO : add explanation of values
|
||||
};
|
||||
|
||||
// -=*# Resource for function OFFSET #*=-
|
||||
const TranslateId SC_OPCODE_OFFSET_ARY[] =
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
ScFunctionListObj::ScFunctionListObj()
|
||||
: UnoApiTest("/sc/qa/extras/testdocuments")
|
||||
, XElementAccess(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get())
|
||||
, XIndexAccess(396)
|
||||
, XIndexAccess(397)
|
||||
, XNameAccess("IF")
|
||||
, XServiceInfo("stardiv.StarCalc.ScFunctionListObj", "com.sun.star.sheet.FunctionDescriptions")
|
||||
{
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2924,6 +2924,7 @@ CPPUNIT_TEST_FIXTURE(Test, testFunctionLists)
|
||||
"STYLE",
|
||||
"VLOOKUP",
|
||||
"XLOOKUP",
|
||||
"XMATCH",
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
||||
@@ -676,6 +676,7 @@ ScFunctionList::ScFunctionList( bool bEnglishFunctionNames )
|
||||
{ SC_OPCODE_ISPMT, ENTRY(SC_OPCODE_ISPMT_ARY), 0, ID_FUNCTION_GRP_FINANCIAL, HID_FUNC_ISPMT, 4, { 0, 0, 0, 0 }, 0 },
|
||||
{ SC_OPCODE_HYPERLINK, ENTRY(SC_OPCODE_HYPERLINK_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_HYPERLINK, 2, { 0, 1 }, 0 },
|
||||
{ SC_OPCODE_X_LOOKUP, ENTRY(SC_OPCODE_X_LOOKUP_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_XLOOKUP_MS, 6, { 0, 0, 0, 1, 1, 1 }, 0 },
|
||||
{ SC_OPCODE_X_MATCH, ENTRY(SC_OPCODE_X_MATCH_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_XMATCH_MS, 4, { 0, 0, 1, 1 }, 0 },
|
||||
{ SC_OPCODE_GET_PIVOT_DATA, ENTRY(SC_OPCODE_GET_PIVOT_DATA_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_GETPIVOTDATA, VAR_ARGS+2, { 0, 0, 1 }, 0 },
|
||||
{ SC_OPCODE_EUROCONVERT, ENTRY(SC_OPCODE_EUROCONVERT_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_EUROCONVERT, 5, { 0, 0, 0, 1, 1 }, 0 },
|
||||
{ SC_OPCODE_NUMBERVALUE, ENTRY(SC_OPCODE_NUMBERVALUE_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_NUMBERVALUE, 3, { 0, 1, 1 }, 0 },
|
||||
|
||||
@@ -206,8 +206,8 @@ void ScQueryCellIteratorBase< accessType, queryType >::PerformQuery()
|
||||
if ( aCell.isEmpty())
|
||||
return;
|
||||
|
||||
// XLookUp: Forward/asc/backward/desc search for best fit value, except if we have an exact match
|
||||
if (nSearchOpCode == SC_OPCODE_X_LOOKUP &&
|
||||
// XLookUp/XMatch: Forward/asc/backward/desc search for best fit value, except if we have an exact match
|
||||
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
|
||||
(rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL) &&
|
||||
(nBestFitCol != nCol || nBestFitRow != nRow))
|
||||
{
|
||||
@@ -315,8 +315,8 @@ void ScQueryCellIteratorBase< accessType, queryType >::InitPos()
|
||||
// non-matching position using SC_LESS and the start position
|
||||
// is the one after it.
|
||||
lastRow = nRow;
|
||||
// BinarySearch() looks for the first match for XLOOKUP
|
||||
if (nSearchOpCode != SC_OPCODE_X_LOOKUP)
|
||||
// BinarySearch() looks for the first match for XLOOKUP/XMATCH
|
||||
if (nSearchOpCode != SC_OPCODE_X_LOOKUP && nSearchOpCode != SC_OPCODE_X_MATCH)
|
||||
{
|
||||
ScQueryOp saveOp = op;
|
||||
op = SC_LESS;
|
||||
@@ -342,7 +342,8 @@ void ScQueryCellIteratorBase< accessType, queryType >::InitPos()
|
||||
if( BinarySearch( nCol ))
|
||||
lastRow = nRow;
|
||||
}
|
||||
AccessBase::InitPosFinish(beforeRow, lastRow, (nSearchOpCode == SC_OPCODE_X_LOOKUP));
|
||||
AccessBase::InitPosFinish(beforeRow, lastRow,
|
||||
(nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,9 +547,9 @@ bool ScQueryCellIteratorBase< accessType, queryType >::BinarySearch( SCCOL col,
|
||||
{
|
||||
if (fLastInRangeValue <= nCellVal)
|
||||
{
|
||||
if (nSearchOpCode == SC_OPCODE_X_LOOKUP &&
|
||||
nSortedBinarySearch != nSearchbDesc &&
|
||||
fLastInRangeValue == nCellVal && aIndexer.getLowIndex() != i)
|
||||
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
|
||||
nSortedBinarySearch != nSearchbDesc && fLastInRangeValue == nCellVal &&
|
||||
aIndexer.getLowIndex() != i)
|
||||
bDone = true;
|
||||
else
|
||||
{
|
||||
@@ -596,9 +597,9 @@ bool ScQueryCellIteratorBase< accessType, queryType >::BinarySearch( SCCOL col,
|
||||
aCellStr);
|
||||
if (nTmp <= 0)
|
||||
{
|
||||
if (nSearchOpCode == SC_OPCODE_X_LOOKUP &&
|
||||
nSortedBinarySearch != nSearchbDesc &&
|
||||
nTmp == 0 && aIndexer.getLowIndex() != i)
|
||||
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
|
||||
nSortedBinarySearch != nSearchbDesc && nTmp == 0 &&
|
||||
aIndexer.getLowIndex() != i)
|
||||
bDone = true;
|
||||
else
|
||||
{
|
||||
@@ -672,8 +673,8 @@ bool ScQueryCellIteratorBase< accessType, queryType >::BinarySearch( SCCOL col,
|
||||
{
|
||||
found = i;
|
||||
nLastInRange = i;
|
||||
if (nSearchOpCode == SC_OPCODE_X_LOOKUP && (nSortedBinarySearch == nSearchbAscd &&
|
||||
(rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_EQUAL)))
|
||||
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
|
||||
(nSortedBinarySearch == nSearchbAscd && (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_EQUAL)))
|
||||
bDone = true;
|
||||
else // But keep searching to find the last matching one.
|
||||
nLo = nMid + 1;
|
||||
@@ -753,8 +754,9 @@ bool ScQueryCellIterator< accessType >::FindEqualOrSortedLastInRange( SCCOL& nFo
|
||||
nFoundCol = rDoc.MaxCol()+1;
|
||||
nFoundRow = rDoc.MaxRow()+1;
|
||||
|
||||
if (nSearchOpCode == SC_OPCODE_X_LOOKUP && nSortedBinarySearch == nBinarySearchDisabled)
|
||||
SetStopOnMismatch( false ); // assume not sorted keys for XLookup
|
||||
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
|
||||
nSortedBinarySearch == nBinarySearchDisabled)
|
||||
SetStopOnMismatch( false ); // assume not sorted keys for XLookup/XMatch
|
||||
else
|
||||
SetStopOnMismatch( true ); // assume sorted keys
|
||||
|
||||
@@ -767,8 +769,8 @@ bool ScQueryCellIterator< accessType >::FindEqualOrSortedLastInRange( SCCOL& nFo
|
||||
(bLiteral || maParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByValue) &&
|
||||
(maParam.GetEntry(0).eOp == SC_LESS_EQUAL || maParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
|
||||
|
||||
// assume not sorted properly if we are using XLookup with forward or backward search
|
||||
if (bBinary && nSearchOpCode == SC_OPCODE_X_LOOKUP &&
|
||||
// assume not sorted properly if we are using XLookup/XMatch with forward or backward search
|
||||
if (bBinary && (nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
|
||||
nSortedBinarySearch == nBinarySearchDisabled)
|
||||
bBinary = false;
|
||||
|
||||
@@ -862,7 +864,8 @@ bool ScQueryCellIterator< accessType >::FindEqualOrSortedLastInRange( SCCOL& nFo
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( IsEqualConditionFulfilled() && nSearchOpCode != SC_OPCODE_X_LOOKUP )
|
||||
if (IsEqualConditionFulfilled() && (nSearchOpCode != SC_OPCODE_X_LOOKUP &&
|
||||
nSearchOpCode != SC_OPCODE_X_MATCH))
|
||||
{
|
||||
// Position on last equal entry, except for XLOOKUP,
|
||||
// which looking for the first equal entry
|
||||
|
||||
@@ -541,7 +541,7 @@ private:
|
||||
inline void TreatDoubleError( double& rVal );
|
||||
// Lookup using ScLookupCache, @returns true if found and result address
|
||||
bool LookupQueryWithCache( ScAddress & o_rResultPos, const ScQueryParam & rParam,
|
||||
const ScComplexRefData* refData, sal_Int8 nSearchMode, sal_Int16 nOpCode ) const;
|
||||
const ScComplexRefData* refData, sal_Int8 nSearchMode, sal_uInt16 nOpCode ) const;
|
||||
|
||||
void ScIfJump();
|
||||
void ScIfError( bool bNAonly );
|
||||
@@ -671,6 +671,7 @@ private:
|
||||
void ScRow();
|
||||
void ScSheet();
|
||||
void ScMatch();
|
||||
void ScXMatch();
|
||||
void IterateParametersIf( ScIterFuncIf );
|
||||
void ScCountIf();
|
||||
void ScSumIf();
|
||||
|
||||
@@ -5075,6 +5075,178 @@ void ScInterpreter::ScMatch()
|
||||
PushIllegalParameter();
|
||||
}
|
||||
|
||||
void ScInterpreter::ScXMatch()
|
||||
{
|
||||
sal_uInt8 nParamCount = GetByte();
|
||||
if (!MustHaveParamCount(nParamCount, 2, 4))
|
||||
return;
|
||||
|
||||
VectorSearchArguments vsa;
|
||||
vsa.nSearchOpCode = SC_OPCODE_X_MATCH;
|
||||
|
||||
// get search mode
|
||||
if (nParamCount == 4)
|
||||
{
|
||||
sal_Int16 k = GetInt16();
|
||||
if (k >= -2 && k <= 2 && k != 0)
|
||||
vsa.eSearchMode = static_cast<SearchMode>(k);
|
||||
else
|
||||
{
|
||||
PushIllegalParameter();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
vsa.eSearchMode = searchfwd;
|
||||
|
||||
// get match mode
|
||||
if (nParamCount >= 3)
|
||||
{
|
||||
sal_Int16 k = GetInt16();
|
||||
if (k >= -1 && k <= 2)
|
||||
vsa.eMatchMode = static_cast<MatchMode>(k);
|
||||
else
|
||||
{
|
||||
PushIllegalParameter();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
vsa.eMatchMode = exactorNA;
|
||||
|
||||
// get vector to be searched
|
||||
switch (GetStackType())
|
||||
{
|
||||
case svSingleRef:
|
||||
{
|
||||
PopSingleRef(vsa.nCol1, vsa.nRow1, vsa.nTab1);
|
||||
vsa.nCol2 = vsa.nCol1;
|
||||
vsa.nRow2 = vsa.nRow1;
|
||||
vsa.pMatSrc = nullptr;
|
||||
}
|
||||
break;
|
||||
case svDoubleRef:
|
||||
{
|
||||
vsa.pMatSrc = nullptr;
|
||||
SCTAB nTab2 = 0;
|
||||
PopDoubleRef(vsa.nCol1, vsa.nRow1, vsa.nTab1, vsa.nCol2, vsa.nRow2, nTab2);
|
||||
if (vsa.nTab1 != nTab2 || (vsa.nCol1 != vsa.nCol2 && vsa.nRow1 != vsa.nRow2))
|
||||
{
|
||||
PushIllegalParameter();
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case svMatrix:
|
||||
case svExternalDoubleRef:
|
||||
{
|
||||
if (GetStackType() == svMatrix)
|
||||
vsa.pMatSrc = PopMatrix();
|
||||
else
|
||||
PopExternalDoubleRef(vsa.pMatSrc);
|
||||
|
||||
if (!vsa.pMatSrc)
|
||||
{
|
||||
PushIllegalParameter();
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PushIllegalParameter();
|
||||
return;
|
||||
}
|
||||
|
||||
// get search value
|
||||
if (nGlobalError == FormulaError::NONE)
|
||||
{
|
||||
switch (GetStackType())
|
||||
{
|
||||
case svDouble:
|
||||
{
|
||||
vsa.isStringSearch = false;
|
||||
vsa.fSearchVal = GetDouble();
|
||||
}
|
||||
break;
|
||||
case svString:
|
||||
{
|
||||
vsa.isStringSearch = true;
|
||||
vsa.sSearchStr = GetString();
|
||||
}
|
||||
break;
|
||||
case svDoubleRef:
|
||||
case svSingleRef:
|
||||
{
|
||||
ScAddress aAdr;
|
||||
if (!PopDoubleRefOrSingleRef(aAdr))
|
||||
{
|
||||
PushInt(0);
|
||||
return;
|
||||
}
|
||||
ScRefCellValue aCell(mrDoc, aAdr);
|
||||
if (aCell.hasNumeric())
|
||||
{
|
||||
vsa.isStringSearch = false;
|
||||
vsa.fSearchVal = GetCellValue(aAdr, aCell);
|
||||
}
|
||||
else
|
||||
{
|
||||
vsa.isStringSearch = true;
|
||||
GetCellString(vsa.sSearchStr, aCell);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case svExternalSingleRef:
|
||||
{
|
||||
ScExternalRefCache::TokenRef pToken;
|
||||
PopExternalSingleRef(pToken);
|
||||
if (nGlobalError != FormulaError::NONE)
|
||||
{
|
||||
PushError(nGlobalError);
|
||||
return;
|
||||
}
|
||||
if (pToken->GetType() == svDouble)
|
||||
{
|
||||
vsa.isStringSearch = false;
|
||||
vsa.fSearchVal = pToken->GetDouble();
|
||||
}
|
||||
else
|
||||
{
|
||||
vsa.isStringSearch = true;
|
||||
vsa.sSearchStr = pToken->GetString();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case svExternalDoubleRef:
|
||||
case svMatrix:
|
||||
{
|
||||
ScMatValType nType = GetDoubleOrStringFromMatrix(
|
||||
vsa.fSearchVal, vsa.sSearchStr);
|
||||
vsa.isStringSearch = ScMatrix::IsNonValueType(nType);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
PushIllegalParameter();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// execute search
|
||||
if (SearchVectorForValue(vsa))
|
||||
PushDouble(vsa.nIndex);
|
||||
else
|
||||
{
|
||||
if (vsa.isResultNA)
|
||||
PushNA();
|
||||
else
|
||||
return; // error occurred and has already been pushed
|
||||
}
|
||||
}
|
||||
else
|
||||
PushIllegalParameter();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool isCellContentEmpty( const ScRefCellValue& rCell )
|
||||
@@ -10741,8 +10913,8 @@ bool ScInterpreter::SearchVectorForValue( VectorSearchArguments& vsa )
|
||||
break;
|
||||
|
||||
case wildcard :
|
||||
// this mode can only used with XLOOKUP
|
||||
if ( vsa.nSearchOpCode == SC_OPCODE_X_LOOKUP )
|
||||
// this mode can only used with XLOOKUP/XMATCH
|
||||
if ( vsa.nSearchOpCode == SC_OPCODE_X_LOOKUP || vsa.nSearchOpCode == SC_OPCODE_X_MATCH )
|
||||
{
|
||||
rEntry.eOp = SC_EQUAL;
|
||||
if ( vsa.isStringSearch )
|
||||
@@ -10833,7 +11005,7 @@ bool ScInterpreter::SearchVectorForValue( VectorSearchArguments& vsa )
|
||||
|
||||
static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument& rDoc, ScInterpreterContext& rContext,
|
||||
const ScQueryParam & rParam, const ScQueryEntry & rEntry, const ScFormulaCell* cell,
|
||||
const ScComplexRefData* refData, sal_Int8 nSearchMode, sal_Int16 nOpCode )
|
||||
const ScComplexRefData* refData, sal_Int8 nSearchMode, sal_uInt16 nOpCode )
|
||||
{
|
||||
if (rEntry.eOp != SC_EQUAL)
|
||||
{
|
||||
@@ -10952,7 +11124,7 @@ static SCROW lcl_getPrevRowWithEmptyValueLookup( const ScLookupCache& rCache,
|
||||
|
||||
bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
|
||||
const ScQueryParam & rParam, const ScComplexRefData* refData,
|
||||
sal_Int8 nSearchMode, sal_Int16 nOpCode ) const
|
||||
sal_Int8 nSearchMode, sal_uInt16 nOpCode ) const
|
||||
{
|
||||
bool bFound = false;
|
||||
const ScQueryEntry& rEntry = rParam.GetEntry(0);
|
||||
|
||||
@@ -4317,6 +4317,7 @@ StackVar ScInterpreter::Interpret()
|
||||
case ocIndirect : ScIndirect(); break;
|
||||
case ocAddress : ScAddressFunc(); break;
|
||||
case ocMatch : ScMatch(); break;
|
||||
case ocXMatch : ScXMatch(); break;
|
||||
case ocCountEmptyCells : ScCountEmptyCells(); break;
|
||||
case ocCountIf : ScCountIf(); break;
|
||||
case ocSumIf : ScSumIf(); break;
|
||||
|
||||
@@ -264,7 +264,8 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
|
||||
{ ocVarS, {{ Reference }, 1, Value }},
|
||||
{ ocWhitespace, {{ Bounds }, 0, Bounds }},
|
||||
{ ocWorkday_MS, {{ Value, Value, Value, Reference }, 0, Value }},
|
||||
{ ocXLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray, Value, Value, Value }, 0, Value }},
|
||||
{ ocXLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray, Value, Value, Value }, 0, Reference }},
|
||||
{ ocXMatch, {{ Value, ReferenceOrForceArray, Value, Value }, 0, Value }},
|
||||
{ ocXor, {{ Reference }, 1, Value }},
|
||||
{ ocZTest, {{ Reference, Value, Value }, 0, Value }},
|
||||
{ ocZTest_MS, {{ Reference, Value, Value }, 0, Value }},
|
||||
|
||||
@@ -1388,6 +1388,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
|
||||
case ocCount2:
|
||||
case ocVLookup:
|
||||
case ocXLookup:
|
||||
case ocXMatch:
|
||||
case ocSLN:
|
||||
case ocIRR:
|
||||
case ocMIRR:
|
||||
|
||||
@@ -601,7 +601,8 @@ const XclFunctionInfo saFuncTable_2016[] =
|
||||
*/
|
||||
const XclFunctionInfo saFuncTable_2021[] =
|
||||
{
|
||||
EXC_FUNCENTRY_V_VR( ocXLookup, 3, 6, 0, "XLOOKUP" )
|
||||
EXC_FUNCENTRY_V_VR( ocXLookup, 3, 6, 0, "XLOOKUP" ),
|
||||
EXC_FUNCENTRY_V_VR( ocXMatch, 2, 4, 0, "XMATCH" )
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -875,7 +875,8 @@ const FunctionData saFuncTable2016[] =
|
||||
/* FIXME: BIFF?? function identifiers available? Where to obtain? */
|
||||
const FunctionData saFuncTable2021[] =
|
||||
{
|
||||
{ "COM.MICROSOFT.XLOOKUP", "XLOOKUP", NOID, NOID, 3, 6, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW }
|
||||
{ "COM.MICROSOFT.XLOOKUP", "XLOOKUP", NOID, NOID, 3, 6, R, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
|
||||
{ "COM.MICROSOFT.XMATCH", "XMATCH", NOID, NOID, 2, 4, V, { VR, VA }, FuncFlags::MACROCALL_NEW }
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user