summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@gmail.com>2013-07-02 22:10:25 -0400
committerKohei Yoshida <kohei.yoshida@gmail.com>2013-07-02 23:14:47 -0400
commitce7a2d39efc66ae682873a96030332b38ba3a4d6 (patch)
tree156f73829cf5844b29b75b9c5977b435505ad7b7 /sc
parent041e7dce8097fe2a4fe1cc853cab463dd5ea72e5 (diff)
Detect circular dependency in formula groups to fallback to cell-based.
Change-Id: Icfb4fd4be4e0c1f6f450fb8ddce57c7b79568e6f
Diffstat (limited to 'sc')
-rw-r--r--sc/inc/formulacell.hxx11
-rw-r--r--sc/inc/types.hxx7
-rw-r--r--sc/source/core/data/column2.cxx20
-rw-r--r--sc/source/core/data/formulacell.cxx46
-rw-r--r--sc/source/core/tool/formulagroup.cxx14
5 files changed, 75 insertions, 23 deletions
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 52a14744d588..07b726ae06f9 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -24,6 +24,7 @@
#include "formula/tokenarray.hxx"
#include "svl/listener.hxx"
+#include "types.hxx"
#include <set>
@@ -40,19 +41,23 @@ struct ScSimilarFormulaDelta;
struct SC_DLLPUBLIC ScFormulaCellGroup
{
- sal_Int32 mnRefCount;
+ mutable size_t mnRefCount;
+
SCROW mnStart; // Start offset of that cell
SCROW mnLength; // How many of these do we have ?
bool mbInvariant;
+ sc::GroupCalcState meCalcState;
ScFormulaCellGroup();
~ScFormulaCellGroup();
};
-inline void intrusive_ptr_add_ref(ScFormulaCellGroup *p)
+
+inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
{
p->mnRefCount++;
}
-inline void intrusive_ptr_release(ScFormulaCellGroup *p)
+
+inline void intrusive_ptr_release(const ScFormulaCellGroup *p)
{
if( --p->mnRefCount == 0 )
delete p;
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 445311e97ea4..5c11da518976 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -56,6 +56,13 @@ const sal_uInt16 MatrixEdgeTop = 8;
const sal_uInt16 MatrixEdgeRight = 16;
const sal_uInt16 MatrixEdgeOpen = 32;
+enum GroupCalcState
+{
+ GroupCalcEnabled,
+ GroupCalcRunning,
+ GroupCalcDisabled
+};
+
}
#endif
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 4becbb750358..82daadf4651d 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2166,10 +2166,15 @@ bool appendDouble(
nLenRemain = 0;
}
+ sal_uInt16 nErr;
+ double fVal;
for (; itData != itDataEnd; ++itData)
{
ScFormulaCell& rFC = **itData;
- rArray.push_back(rFC.GetValue());
+ if (!rFC.GetErrorOrValue(nErr, fVal) || nErr)
+ return false;
+
+ rArray.push_back(fVal);
}
}
break;
@@ -2238,6 +2243,9 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
break;
case sc::element_type_formula:
{
+ sal_uInt16 nErr;
+ double fVal;
+
rCxt.maArrays.push_back(new sc::FormulaGroupContext::DoubleArrayType);
sc::FormulaGroupContext::DoubleArrayType& rArray = rCxt.maArrays.back();
rArray.reserve(nLenRequested);
@@ -2252,7 +2260,10 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
for (; it != itEnd; ++it)
{
ScFormulaCell& rCell = **it;
- rArray.push_back(rCell.GetValue()); // the cell may be interpreted.
+ if (!rCell.GetErrorOrValue(nErr, fVal) || nErr)
+ return NULL;
+
+ rArray.push_back(fVal);
}
return &rArray[0];
@@ -2264,7 +2275,10 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n
for (; it != itEnd; ++it)
{
ScFormulaCell& rCell = **it;
- rArray.push_back(rCell.GetValue()); // the cell may be interpreted.
+ if (!rCell.GetErrorOrValue(nErr, fVal) || nErr)
+ return NULL;
+
+ rArray.push_back(fVal);
}
// Fill the remaining array with values from the following blocks.
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index a1297261efd2..132ed5cb620c 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -382,7 +382,11 @@ void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldD
}
ScFormulaCellGroup::ScFormulaCellGroup() :
- mnRefCount(0), mnStart(0), mnLength(0), mbInvariant(false)
+ mnRefCount(0),
+ mnStart(0),
+ mnLength(0),
+ mbInvariant(false),
+ meCalcState(sc::GroupCalcEnabled)
{
}
@@ -1547,6 +1551,9 @@ void ScFormulaCell::SetDirty( bool bDirtyFlag )
void ScFormulaCell::SetDirtyVar()
{
bDirty = true;
+ if (xGroup)
+ xGroup->meCalcState = sc::GroupCalcEnabled;
+
// mark the sheet of this cell to be calculated
//#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() );
}
@@ -1611,7 +1618,7 @@ void ScFormulaCell::SetErrCode( sal_uInt16 n )
void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
{
if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
- bDirty = true;
+ SetDirtyVar();
if ( nBits & RECALCMODE_ONLOAD_ONCE )
{ // OnLoadOnce nur zum Dirty setzen nach Filter-Import
nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
@@ -2959,9 +2966,10 @@ class GroupTokenConverter
ScTokenArray& mrGroupTokens;
ScDocument& mrDoc;
ScFormulaCell& mrCell;
+ const ScAddress& mrPos;
public:
- GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell) :
- mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell) {}
+ GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
+ mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {}
bool convert(ScTokenArray& rCode)
{
@@ -2979,8 +2987,7 @@ public:
case svSingleRef:
{
ScSingleRefData aRef = pToken->GetSingleRef();
- aRef.CalcAbsIfRel(mrCell.aPos);
- ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab);
+ ScAddress aRefPos = aRef.toAbs(mrPos);
if (aRef.IsRowRel())
{
// Fetch double array guarantees that the length of the
@@ -3108,6 +3115,13 @@ bool ScFormulaCell::InterpretFormulaGroup()
if (!xGroup || !pCode)
return false;
+ fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: calc state = %d\n", xGroup->meCalcState);
+ if (xGroup->meCalcState == sc::GroupCalcDisabled)
+ {
+ fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: group calc disabled.\n");
+ return false;
+ }
+
switch (pCode->GetVectorState())
{
case FormulaVectorEnabled:
@@ -3126,10 +3140,26 @@ bool ScFormulaCell::InterpretFormulaGroup()
sc::FormulaGroupContext aCxt;
ScTokenArray aCode;
- GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this);
+ ScAddress aTopPos = aPos;
+ aTopPos.SetRow(xGroup->mnStart);
+ GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this, aTopPos);
if (!aConverter.convert(*pCode))
+ {
+ fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: disabling group calc due to failed conversion\n");
+ xGroup->meCalcState = sc::GroupCalcDisabled;
+ return false;
+ }
+
+ xGroup->meCalcState = sc::GroupCalcRunning;
+ if (!sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aTopPos, xGroup, aCode))
+ {
+ fprintf(stdout, "ScFormulaCell::InterpretFormulaGroup: disabling group calc due to failed calculation\n");
+ xGroup->meCalcState = sc::GroupCalcDisabled;
return false;
- return sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aPos, xGroup, aCode);
+ }
+
+ xGroup->meCalcState = sc::GroupCalcEnabled;
+ return true;
}
bool ScFormulaCell::InterpretInvariantFormulaGroup()
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 79621eabdffd..b20b4377e884 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -33,18 +33,14 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
{
// Decompose the group into individual cells and calculate them individually.
- // Always set the top row to be the top of the group. Grouped formula
- // cells are to be calculated for its full segment at all times.
-
- ScAddress aTopPos = rTopPos;
- aTopPos.SetRow(xGroup->mnStart);
- ScAddress aTmpPos = aTopPos;
+ // The caller must ensure that the top position is the start position of
+ // the group.
+ ScAddress aTmpPos = rTopPos;
std::vector<double> aResults;
aResults.reserve(xGroup->mnLength);
- for (SCROW i = 0; i < xGroup->mnLength; ++i)
+ for (SCROW i = 0; i < xGroup->mnLength; ++i, aTmpPos.IncRow())
{
- aTmpPos.SetRow(aTopPos.Row() + i);
ScTokenArray aCode2;
for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
{
@@ -103,7 +99,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
} // for loop end (xGroup->mnLength)
if (!aResults.empty())
- rDoc.SetFormulaResults(aTopPos, &aResults[0], aResults.size());
+ rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size());
return true;
}