Index: source/core/tool/interpr1.cxx =================================================================== --- source/core/tool/interpr1.cxx (revision 271413) +++ source/core/tool/interpr1.cxx (working copy) @@ -4681,10 +4681,16 @@ void ScInterpreter::ScLookup() } } + // For double, string and single reference. + double nDataVal; + String aDataStr; + bool bValueData = false; + // Get the data-result range and also determine whether this is vertical // lookup or horizontal lookup. - switch (GetStackType()) + StackVar eDataArrayType = GetStackType(); + switch (eDataArrayType) { case svDoubleRef: { @@ -4714,6 +4720,36 @@ void ScInterpreter::ScLookup() nLenMajor = bVertical ? nR : nC; } break; + case svDouble: + { + nDataVal = GetDouble(); + bValueData = true; + } + break; + case svString: + { + aDataStr = GetString(); + } + break; + case svSingleRef: + { + ScAddress aDataAdr; + PopSingleRef( aDataAdr ); + const ScBaseCell* pDataCell = GetCell( aDataAdr ); + if ( HasCellValueData( pDataCell ) ) + { + nDataVal = GetCellValue( aDataAdr, pDataCell ); + bValueData = true; + } + else if ( GetCellType( pDataCell ) == CELLTYPE_NONE ) + { + nDataVal = 0.0; + bValueData = true; + } + else + GetCellString( aDataStr, pDataCell ); + } + break; default: PushIllegalParameter(); return; @@ -4733,6 +4769,66 @@ void ScInterpreter::ScLookup() if ( !FillEntry(rEntry) ) return; + if ( eDataArrayType == svDouble || eDataArrayType == svString + || eDataArrayType == svSingleRef ) + { + // Delta position for a single value is always 0. + + // Found if data <= query, but not if query is string and found data is + // numeric or vice versa. This is how Excel does it but doesn't + // document it. + + bool bFound = false; + if ( bValueData ) + { + if ( rEntry.bQueryByString ) + bFound = false; + else + bFound = (nDataVal <= rEntry.nVal); + } + else + { + if ( !rEntry.bQueryByString ) + bFound = false; + else + { + sal_Int32 nCompare = ScGlobal::pCollator->compareString( + aDataStr, *rEntry.pStr ); + bFound = (nCompare <= 0); + } + } + + if (!bFound) + { + PushNA(); + return; + } + + if (pResMat) + { + if (pResMat->IsValue( 0 )) + PushDouble(pResMat->GetDouble( 0 )); + else + PushString(pResMat->GetString( 0 )); + } + else if (nParamCount == 3) + { + ScAddress aAdr; + aAdr.SetTab( nResTab); + aAdr.SetCol( nResCol1); + aAdr.SetRow( nResRow1); + PushCellResultToken( true, aAdr, NULL, NULL); + } + else + { + if ( bValueData ) + PushDouble( nDataVal ); + else + PushString( aDataStr ); + } + return; + } + // Now, perform the search to compute the delta position (nDelta). if (pDataMat) @@ -4818,6 +4914,20 @@ void ScInterpreter::ScLookup() bFound = true; } + // With 0-9 < A-Z, if query is numeric and data found is string, or + // vice versa, the (yet another undocumented) Excel behavior is to + // return #N/A instead. + + if (bFound) + { + SCCOLROW i = nDelta; + SCSIZE n = pDataMat->GetElementCount(); + if (static_cast(i) >= n) + i = static_cast(n); + if (bool(rEntry.bQueryByString) == bool(pDataMat->IsValue(i))) + bFound = false; + } + if (!bFound) { PushNA(); Index: source/core/tool/parclass.cxx =================================================================== --- source/core/tool/parclass.cxx (revision 269325) +++ source/core/tool/parclass.cxx (working copy) @@ -130,7 +130,7 @@ const ScParameterClassification::RawData ScParamet { ocLarge, {{ Reference, Value }, false }}, { ocLess, {{ Array, Array }, false }}, { ocLessEqual, {{ Array, Array }, false }}, - { ocLookup, {{ Value, Reference, Reference }, false }}, + { ocLookup, {{ Value, ForceArray, ForceArray }, false }}, { ocMatch, {{ Value, Reference, Reference }, false }}, { ocMatDet, {{ ForceArray }, false }}, { ocMatInv, {{ ForceArray }, false }},