[ooo-build-commit] Branch 'ooo-build-3-1' - patches/dev300

Kohei Yoshida kohei at kemper.freedesktop.org
Wed Jul 15 12:09:05 PDT 2009


 patches/dev300/apply                                   |   12 
 patches/dev300/calc-formula-externref-countif-fix.diff |  728 +++++++++++++++++
 2 files changed, 729 insertions(+), 11 deletions(-)

New commits:
commit 4f3e960ad1ededa86c8ed75d7703fa921029673d
Author: Kohei Yoshida <kyoshida at novell.com>
Date:   Wed Jul 15 14:34:16 2009 -0400

    COUNTIF now works with external references.
    
    * patches/dev300/apply: removed all patches but the one below from
      the CalcExperimental section.  All the other patches are already
      enabled on master.
    
    * patches/dev300/calc-formula-externref-countif-fix.diff: external
      reference tokens are pre-processed and pushed as static values.
      So, ScCountIf() needs to handle static values (which are in fact
      external reference values) in order to handle them properly.
      (n#521624, i#102750)

diff --git a/patches/dev300/apply b/patches/dev300/apply
index b69c882..c339400 100644
--- a/patches/dev300/apply
+++ b/patches/dev300/apply
@@ -3027,17 +3027,7 @@ calc-delete-note-cell-crasher.diff, n#517566, kohei
 
 [ CalcExperimental ]
 
-# speed up sheet switch operation.
-calc-perf-sheet-switch.diff, n#495140, kohei
-
-# support custom sort in datapilot tables.
-calc-dp-custom-sort.diff, n#443361, kohei
-
-# support ods import/export of sheet options and password hash.
-calc-ods-sheet-protection-sc.diff,      i#60305, i#71468, kohei
-calc-ods-sheet-protection-xmloff.diff,  i#60305, i#71468, kohei
-calc-ods-sheet-protection-svtools.diff, i#60305, i#71468, kohei
-
+calc-formula-externref-countif-fix.diff, n#521624, i#102750, kohei
 
 [ UbuntuHardyOnly ]
 # Add patch to only show local files needed when gnome-vfs/gio is disabled
diff --git a/patches/dev300/calc-formula-externref-countif-fix.diff b/patches/dev300/calc-formula-externref-countif-fix.diff
new file mode 100644
index 0000000..2be4194
--- /dev/null
+++ b/patches/dev300/calc-formula-externref-countif-fix.diff
@@ -0,0 +1,728 @@
+diff --git sc/source/core/inc/funcqueryhandler.hxx sc/source/core/inc/funcqueryhandler.hxx
+new file mode 100644
+index 0000000..2cb28c5
+--- /dev/null
++++ sc/source/core/inc/funcqueryhandler.hxx
+@@ -0,0 +1,140 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: opcode.hxx,v $
++ * $Revision: 1.23.134.2 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef SC_FUNC_QUERY_HANDLER_HXX
++#define SC_FUNC_QUERY_HANDLER_HXX
++
++#include "global.hxx"
++#include <vector>
++#include <boost/shared_ptr.hpp>
++
++namespace utl {
++    class SearchParam;
++    class TextSearch;
++}
++
++class ScBaseCell;
++
++class ScFunctionQueryHandler
++{
++public:
++
++    struct QueryOption
++    {
++        ScQueryOp       meOp;
++        ::rtl::OUString maMatchString;
++        double          mfMatchValue;
++        bool            mbQueryByString;
++        bool            mbRegExp;
++
++        // Caching these instances for regexp searches.
++        ::boost::shared_ptr< ::utl::SearchParam> mpSearchParam;
++        ::boost::shared_ptr< ::utl::TextSearch>  mpTextSearch;
++
++        void            parseCriterion(const ::rtl::OUString& rStr);
++
++        QueryOption();
++    };
++
++    class DataArrayBase
++    {
++    public:
++        virtual ~DataArrayBase() = 0;
++        virtual bool runQuery(const QueryOption& rOption) = 0;
++        virtual size_t countMatchedCells() const = 0;
++    };
++
++    /** Individual cell of StaticDataArray */
++    struct Cell
++    {
++        ::rtl::OUString maString;
++        double          mfValue;
++        bool            mbIsValue;
++
++        bool match(const QueryOption& rOption) const;
++
++        Cell();
++    };
++
++    /** Data array consisting of static values. */
++    class StaticDataArray : public DataArrayBase
++    {
++    public:
++        virtual ~StaticDataArray();
++
++        void addCell(const ::rtl::OUString& rStr);
++        void addCell(double fVal);
++
++        virtual bool runQuery(const QueryOption& rOption);
++        virtual size_t countMatchedCells() const;
++    private:
++        ::std::vector<Cell>     maDataArray;
++        ::std::vector<size_t>   maMatchedCells;
++    };
++
++    /** Data array for internal cell range. */
++    class RangeDataArray : public DataArrayBase
++    {
++    public:
++        explicit RangeDataArray(ScDocument* pDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab);
++        virtual ~RangeDataArray();
++
++        virtual bool runQuery(const QueryOption &rOption);
++        virtual size_t countMatchedCells() const;
++    private:
++        ::std::vector<ScBaseCell*>  maMatchedCells;
++        ScRange     maRange;
++        ScDocument* mpDoc;
++    };
++
++    ScFunctionQueryHandler();
++    ~ScFunctionQueryHandler();
++
++    /** 
++     * @param pArray pointer to <i>unmanaged</i> instance of DataArrayBase. 
++     *               Don't delete this instance in the client code since the
++     *               query handler instance manages the life cycle of this
++     *               data array instance.
++     */
++    void setDataArray(DataArrayBase* pArray);
++    void setQueryOption(const QueryOption& rOption);
++
++    /** 
++     * @return bool true if the query is successful, false otherwise.
++     */
++    bool runQuery();
++    size_t countMatchedCells() const;
++
++private:
++    ::boost::shared_ptr<DataArrayBase>  mpDataArray;
++    QueryOption                         maOption;
++};
++
++#endif
+diff --git sc/source/core/tool/funcqueryhandler.cxx sc/source/core/tool/funcqueryhandler.cxx
+new file mode 100644
+index 0000000..48fdb5a
+--- /dev/null
++++ sc/source/core/tool/funcqueryhandler.cxx
+@@ -0,0 +1,353 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ * 
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: opcode.hxx,v $
++ * $Revision: 1.23.134.2 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org.  If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_sc.hxx"
++
++// INCLUDE ---------------------------------------------------------------
++
++#include "funcqueryhandler.hxx"
++#include "dociter.hxx"
++#include "cell.hxx"
++#include "document.hxx"
++#include "unotools/textsearch.hxx"
++#include "rtl/math.hxx"
++
++#include <memory>
++
++using ::utl::SearchParam;
++using ::utl::TextSearch;
++using ::rtl::OUString;
++using ::std::vector;
++using ::std::auto_ptr;
++
++
++namespace {
++
++bool evaluateValue(const ScFunctionQueryHandler::QueryOption& rOption, double fVal)
++{
++    bool bMatch = false;
++    switch (rOption.meOp)
++    {
++        using ::rtl::math::approxEqual;
++
++        case SC_EQUAL:
++            bMatch = approxEqual(rOption.mfMatchValue, fVal);
++        break;
++        case SC_NOT_EQUAL:
++            bMatch = !approxEqual(rOption.mfMatchValue, fVal);
++        break;
++        case SC_GREATER:
++            bMatch = rOption.mfMatchValue < fVal && !approxEqual(rOption.mfMatchValue, fVal);
++        break;
++        case SC_LESS:
++            bMatch = rOption.mfMatchValue > fVal && !approxEqual(rOption.mfMatchValue, fVal);
++        break;
++        case SC_GREATER_EQUAL:
++            bMatch = rOption.mfMatchValue < fVal || approxEqual(rOption.mfMatchValue, fVal);
++        break;
++        case SC_LESS_EQUAL:
++            bMatch = rOption.mfMatchValue > fVal || approxEqual(rOption.mfMatchValue, fVal);
++        break;
++        default:
++            ;
++    }
++    return bMatch;
++}
++
++bool evaluateString(const ScFunctionQueryHandler::QueryOption& rOption, const OUString& rStr)
++{
++    bool bMatch = false;
++    if (rOption.mbRegExp && rOption.mpTextSearch)
++    {
++        // Regular expression search always uses equal condition.  Note also 
++        // that the matched segment equals the whole string.
++        sal_Int32 nLen = rStr.getLength();
++        xub_StrLen nStart = 0, nEnd = 0;
++        bMatch = rOption.mpTextSearch->SearchFrwrd(rStr, &nStart, &nEnd) && nStart == 0 && nEnd == nLen;
++    }
++    else
++    {
++        switch (rOption.meOp)
++        {
++            case SC_EQUAL:
++                bMatch = rOption.maMatchString.equals(rStr);
++            break;
++            case SC_NOT_EQUAL:
++                bMatch = !rOption.maMatchString.equals(rStr);
++            break;
++            default:
++                ;
++        }
++    }
++    return bMatch;
++}
++
++}
++
++// ============================================================================
++
++void ScFunctionQueryHandler::QueryOption::parseCriterion(const OUString& rStr)
++{
++    // This function is largely inspired by & functionally equivalent to 
++    // ScQueryParam::FillInExcelSyntax().
++
++    maMatchString = rStr;
++    const sal_Unicode* p = rStr.getStr();
++    sal_Int32 n = rStr.getLength();
++    if (!n)
++        return;
++
++    QueryOption aNewOption;
++
++    const sal_Unicode c0 = p[0];
++    if (c0 == '<')
++    {
++        if (n < 2)
++            return;
++
++        const sal_Unicode c1 = p[1];
++        if (c1 == '>')
++        {
++            aNewOption.maMatchString = rStr.copy(2);
++            aNewOption.meOp = SC_NOT_EQUAL;
++        }
++        else if (c1 == '=')
++        {
++            aNewOption.maMatchString = rStr.copy(2);
++            aNewOption.meOp = SC_LESS_EQUAL;
++        }
++        else
++        {
++            aNewOption.maMatchString = rStr.copy(1);
++            aNewOption.meOp = SC_LESS;
++        }
++    }
++    else if (c0 == '>')
++    {
++        if (n < 2)
++            return;
++
++        const sal_Unicode c1 = p[1];
++        if (c1 == '=')
++        {
++            aNewOption.maMatchString = rStr.copy(2);
++            aNewOption.meOp = SC_GREATER_EQUAL;
++        }
++        else
++        {
++            aNewOption.maMatchString = rStr.copy(1);
++            aNewOption.meOp = SC_GREATER;
++        }
++    }
++    else
++    {
++        aNewOption.meOp = SC_EQUAL;
++        if (c0 == '=')
++            aNewOption.maMatchString = rStr.copy(1);
++        else
++            aNewOption.maMatchString = rStr;
++    }
++
++    maMatchString = aNewOption.maMatchString;
++    meOp = aNewOption.meOp;
++}
++
++ScFunctionQueryHandler::QueryOption::QueryOption() :
++    meOp(SC_EQUAL),
++    mbQueryByString(true),
++    mbRegExp(false),
++    mpSearchParam(static_cast<SearchParam*>(NULL)),
++    mpTextSearch(static_cast<TextSearch*>(NULL))
++{
++}
++
++// ----------------------------------------------------------------------------
++
++ScFunctionQueryHandler::DataArrayBase::~DataArrayBase() {}
++
++// ----------------------------------------------------------------------------
++
++bool ScFunctionQueryHandler::Cell::match(const QueryOption& rOption) const
++{
++    if (rOption.mbQueryByString)
++    {
++        if (mbIsValue)
++            return false;
++
++        return evaluateString(rOption, maString);
++    }
++    else
++    {
++        if (!mbIsValue)
++            return false;
++
++        return evaluateValue(rOption, mfValue);
++    }
++}
++
++ScFunctionQueryHandler::Cell::Cell() :
++    mfValue(0.0),
++    mbIsValue(false)
++{
++}
++
++// ----------------------------------------------------------------------------
++
++ScFunctionQueryHandler::StaticDataArray::~StaticDataArray() {}
++
++void ScFunctionQueryHandler::StaticDataArray::addCell(const OUString& rStr)
++{
++    Cell cell;
++    cell.maString = rStr;
++    cell.mfValue = 0.0;
++    cell.mbIsValue = false;
++    maDataArray.push_back(cell);
++}
++
++void ScFunctionQueryHandler::StaticDataArray::addCell(double fVal)
++{
++    Cell cell;
++    cell.mfValue = fVal;
++    cell.mbIsValue = true;
++    maDataArray.push_back(cell);
++}
++
++bool ScFunctionQueryHandler::StaticDataArray::runQuery(const QueryOption& rOption)
++{
++    using ::std::distance;
++
++    maMatchedCells.clear();
++    vector<Cell>::const_iterator itrBeg = maDataArray.begin(), itrEnd = maDataArray.end();
++    for (vector<Cell>::const_iterator itr = itrBeg; itr != itrEnd; ++itr)
++    {
++        if ((*itr).match(rOption))
++        {
++            size_t index = distance(itrBeg, itr);
++            maMatchedCells.push_back(index);
++        }
++    }
++    return true;
++}
++
++size_t ScFunctionQueryHandler::StaticDataArray::countMatchedCells() const
++{
++    return maMatchedCells.size();
++}
++
++// ----------------------------------------------------------------------------
++
++ScFunctionQueryHandler::RangeDataArray::RangeDataArray(ScDocument* pDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab) :
++    maRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab),
++    mpDoc(pDoc)
++{
++}
++
++ScFunctionQueryHandler::RangeDataArray::~RangeDataArray() {}
++
++bool ScFunctionQueryHandler::RangeDataArray::runQuery(const QueryOption& rOption)
++{
++    ScCellIterator aIter(mpDoc, maRange);
++    for (ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext())
++    {
++        bool bMatch = false;
++        if (!rOption.mbQueryByString && mpDoc->HasValueData(aIter.GetCol(), aIter.GetRow(), aIter.GetTab()))
++        {
++            // By Value
++            double fVal = 0.0;
++            mpDoc->GetValue(aIter.GetCol(), aIter.GetRow(), aIter.GetTab(), fVal);
++            bMatch = evaluateValue(rOption, fVal);
++        }
++        else
++        {
++            String aCellStr;
++            mpDoc->GetString(aIter.GetCol(), aIter.GetRow(), aIter.GetTab(), aCellStr);
++            bMatch = evaluateString(rOption, aCellStr);
++        }
++        if (bMatch)
++            maMatchedCells.push_back(pCell);
++    }
++    return true;
++}
++
++size_t ScFunctionQueryHandler::RangeDataArray::countMatchedCells() const
++{
++    return maMatchedCells.size();
++}
++
++// ----------------------------------------------------------------------------
++
++ScFunctionQueryHandler::ScFunctionQueryHandler()
++{
++}
++
++ScFunctionQueryHandler::~ScFunctionQueryHandler()
++{
++}
++
++void ScFunctionQueryHandler::setDataArray(DataArrayBase* pArray)
++{
++    mpDataArray.reset(pArray);
++}
++
++void ScFunctionQueryHandler::setQueryOption(const QueryOption& rOption)
++{
++    maOption = rOption;
++}
++
++bool ScFunctionQueryHandler::runQuery()
++{
++    using ::std::distance;
++
++    if (!mpDataArray)
++        // No data array.
++        return false;
++
++    if (maOption.mbRegExp)
++    {
++        if (!maOption.mpSearchParam)
++            maOption.mpSearchParam.reset(
++                new SearchParam(maOption.maMatchString, ::utl::SearchParam::SRCH_REGEXP, false, false, false));
++        if (!maOption.mpTextSearch)
++            maOption.mpTextSearch.reset(
++                new TextSearch(*maOption.mpSearchParam, *ScGlobal::pCharClass));
++    }
++
++    return mpDataArray->runQuery(maOption);
++}
++
++size_t ScFunctionQueryHandler::countMatchedCells() const
++{
++    if (!mpDataArray)
++        return 0;
++
++    return mpDataArray->countMatchedCells();
++}
++
+diff --git sc/source/core/tool/interpr1.cxx sc/source/core/tool/interpr1.cxx
+index a22d157..9f3bdeb 100644
+--- sc/source/core/tool/interpr1.cxx
++++ sc/source/core/tool/interpr1.cxx
+@@ -67,10 +67,12 @@
+ #include <string.h>
+ #include <math.h>
+ #include <vector>
++#include <memory>
+ #include "cellkeytranslator.hxx"
+ #include "lookupcache.hxx"
+ #include "rangenam.hxx"
+ #include "compiler.hxx"
++#include "funcqueryhandler.hxx"
+ #include <basic/sbstar.hxx>
+ 
+ #define SC_DOUBLE_MAXVALUE  1.7e307
+@@ -4306,85 +4308,125 @@ void ScInterpreter::ScCountIf()
+         size_t nRefInList = 0;
+         while (nParam-- > 0)
+         {
+-            SCCOL nCol1;
+-            SCROW nRow1;
+-            SCTAB nTab1;
+-            SCCOL nCol2;
+-            SCROW nRow2;
+-            SCTAB nTab2;
+-            switch ( GetStackType() )
++            ScFunctionQueryHandler aQueryHdl;
++
++            // Query option first.
++            ScFunctionQueryHandler::QueryOption aOption;
++            if (!bIsString)
+             {
+-                case svDoubleRef :
+-                case svRefList :
+-                    {
+-                        ScRange aRange;
+-                        PopDoubleRef( aRange, nParam, nRefInList);
+-                        aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+-                    }
+-                    break;
+-                case svSingleRef :
+-                    PopSingleRef( nCol1, nRow1, nTab1 );
+-                    nCol2 = nCol1;
+-                    nRow2 = nRow1;
+-                    nTab2 = nTab1;
+-                    break;
+-                default:
+-                    PushIllegalParameter();
+-                    return ;
++                aOption.meOp = SC_EQUAL;
++                aOption.mfMatchValue = fVal;
++                aOption.mbQueryByString = false;
+             }
+-            if ( nTab1 != nTab2 )
++            else
+             {
+-                PushIllegalParameter();
+-                return;
++                aOption.parseCriterion(rString);
++                sal_uInt32 nIndex = 0;
++                aOption.mbQueryByString = 
++                    !(pFormatter->IsNumberFormat(aOption.maMatchString, nIndex, aOption.mfMatchValue));
++                if (aOption.mbQueryByString)
++                    aOption.mbRegExp = MayBeRegExp(aOption.maMatchString, pDok);
+             }
+-            if (nCol1 > nCol2)
++            aQueryHdl.setQueryOption(aOption);
++
++            StackVar eParamType = GetStackType();
++            bool bInternalRef = false;
++            switch (eParamType)
+             {
+-                PushIllegalParameter();
+-                return;
++                case svDoubleRef:
++                case svRefList:
++                case svSingleRef:
++                    bInternalRef = true;
++                break;
+             }
+-            if (nGlobalError == 0)
++            if (bInternalRef)
+             {
+-                ScQueryParam rParam;
+-                rParam.nRow1       = nRow1;
+-                rParam.nRow2       = nRow2;
++                SCCOL nCol1;
++                SCROW nRow1;
++                SCTAB nTab1;
++                SCCOL nCol2;
++                SCROW nRow2;
++                SCTAB nTab2;
+ 
+-                ScQueryEntry& rEntry = rParam.GetEntry(0);
+-                rEntry.bDoQuery = TRUE;
+-                if (!bIsString)
++                switch (eParamType)
+                 {
+-                    rEntry.bQueryByString = FALSE;
+-                    rEntry.nVal = fVal;
+-                    rEntry.eOp = SC_EQUAL;
++                    case svDoubleRef :
++                    case svRefList :
++                        {
++                            ScRange aRange;
++                            PopDoubleRef( aRange, nParam, nRefInList);
++                            aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
++                        }
++                        break;
++                    case svSingleRef :
++                        PopSingleRef( nCol1, nRow1, nTab1 );
++                        nCol2 = nCol1;
++                        nRow2 = nRow1;
++                        nTab2 = nTab1;
++                        break;
++                    break;
++                        PushIllegalParameter();
++                        return ;
+                 }
+-                else
++                if ( nTab1 != nTab2 )
+                 {
+-                    rParam.FillInExcelSyntax(rString, 0);
+-                    sal_uInt32 nIndex = 0;
+-                    rEntry.bQueryByString =
+-                        !(pFormatter->IsNumberFormat(
+-                                    *rEntry.pStr, nIndex, rEntry.nVal));
+-                    if ( rEntry.bQueryByString )
+-                        rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
++                    PushIllegalParameter();
++                    return;
+                 }
+-                rParam.nCol1  = nCol1;
+-                rParam.nCol2  = nCol2;
+-                rEntry.nField = nCol1;
+-                ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
+-                // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
+-                aCellIter.SetAdvanceQueryParamEntryField( TRUE );
+-                if ( aCellIter.GetFirst() )
++                if (nCol1 > nCol2)
+                 {
+-                    do
+-                    {
+-                        fSum++;
+-                    } while ( aCellIter.GetNext() );
++                    PushIllegalParameter();
++                    return;
++                }
++                if (nGlobalError)
++                {
++                    PushIllegalParameter();
++                    return;
+                 }
++
++                aQueryHdl.setDataArray(
++                    new ScFunctionQueryHandler::RangeDataArray(pDok, nCol1, nRow1, nCol2, nRow2, nTab1));
+             }
+             else
+             {
+-                PushIllegalParameter();
+-                return;
++                // Not an internal reference.  Use static data array.
++                ::std::auto_ptr<ScFunctionQueryHandler::DataArrayBase> pDataArray(
++                    new ScFunctionQueryHandler::StaticDataArray);
++                ScFunctionQueryHandler::StaticDataArray* pStaticArray = 
++                    static_cast<ScFunctionQueryHandler::StaticDataArray*>(pDataArray.get());
++                switch (eParamType)
++                {
++                    case svString:
++                        pStaticArray->addCell(GetString());
++                    break;
++                    case svDouble:
++                        pStaticArray->addCell(GetDouble());
++                    break;
++                    case svMatrix:
++                    {
++                        ScMatrixRef xMat = GetMatrix();
++                        SCSIZE n = xMat->GetElementCount();
++                        for (SCSIZE i = 0; i < n; ++i)
++                        {
++                            if (xMat->IsEmpty(i))
++                                // empty cells are not taken into account.
++                                continue;
++
++                            if (xMat->IsValue(i))
++                                pStaticArray->addCell(xMat->GetDouble(i));
++                            else
++                                pStaticArray->addCell(xMat->GetString(i));
++                        }
++                    }
++                    break;
++                    default:
++                        ;
++                }
++                aQueryHdl.setDataArray(pDataArray.release());
+             }
++
++            if (aQueryHdl.runQuery())
++                fSum += aQueryHdl.countMatchedCells();
+         }
+         PushDouble(fSum);
+     }
+diff --git sc/source/core/tool/makefile.mk sc/source/core/tool/makefile.mk
+index 898c2ef..85065d9 100644
+--- sc/source/core/tool/makefile.mk
++++ sc/source/core/tool/makefile.mk
+@@ -107,6 +107,7 @@ SLOFILES =  \
+         $(SLO)$/refupdat.obj \
+         $(SLO)$/scmatrix.obj \
+         $(SLO)$/sctictac.obj \
++        $(SLO)$/funcqueryhandler.obj \
+         $(SLO)$/subtotal.obj \
+         $(SLO)$/token.obj \
+ 		$(SLO)$/unitconv.obj \
+@@ -131,5 +132,6 @@ EXCEPTIONSFILES= \
+         $(SLO)$/lookupcache.obj \
+         $(SLO)$/prnsave.obj \
+ 		$(SLO)$/reftokenhelper.obj \
++        $(SLO)$/funcqueryhandler.obj \
+         $(SLO)$/token.obj
+ 


More information about the ooo-build-commit mailing list