merge the formfield patch from ooo-build
[ooovba.git] / sc / source / core / data / dpcachetable.cxx
blob23bdc951102f661a695fc4e66cf77febe1048cd1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dpcachetable.cxx,v $
11 * $Revision: 1.6 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include "dpcachetable.hxx"
35 #include "document.hxx"
36 #include "address.hxx"
37 #include "cell.hxx"
38 #include "dptabdat.hxx"
39 #include "dptabsrc.hxx"
40 #include "dpobject.hxx"
41 #include "queryparam.hxx"
43 #include <com/sun/star/i18n/LocaleDataItem.hpp>
44 #include <com/sun/star/sdbc/DataType.hpp>
45 #include <com/sun/star/sdbc/XRow.hpp>
46 #include <com/sun/star/sdbc/XRowSet.hpp>
47 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
48 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
49 #include <com/sun/star/util/Date.hpp>
50 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
51 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
53 #include <memory>
55 using namespace ::com::sun::star;
57 using ::rtl::OUString;
58 using ::std::vector;
59 using ::std::pair;
60 using ::std::hash_map;
61 using ::std::hash_set;
62 using ::std::auto_ptr;
63 using ::com::sun::star::i18n::LocaleDataItem;
64 using ::com::sun::star::uno::Exception;
65 using ::com::sun::star::uno::Reference;
66 using ::com::sun::star::uno::Sequence;
67 using ::com::sun::star::uno::Any;
68 using ::com::sun::star::uno::UNO_QUERY;
69 using ::com::sun::star::uno::UNO_QUERY_THROW;
70 using ::com::sun::star::sheet::DataPilotFieldFilter;
72 const double D_TIMEFACTOR = 86400.0;
74 static BOOL lcl_HasQueryEntry( const ScQueryParam& rParam )
76 return rParam.GetEntryCount() > 0 &&
77 rParam.GetEntry(0).bDoQuery;
80 // ----------------------------------------------------------------------------
82 static ScDPCacheCell EmptyCellContent = ScDPCacheCell();
84 // ----------------------------------------------------------------------------
86 ScDPCacheTable::Cell::Cell() :
87 mnCategoryRef(0),
88 mpContent(NULL)
92 ScDPCacheTable::Cell::~Cell()
96 // ----------------------------------------------------------------------------
98 ScDPCacheTable::FilterItem::FilterItem() :
99 mnMatchStrId(ScSimpleSharedString::EMPTY),
100 mfValue(0.0),
101 mbHasValue(false)
105 // ----------------------------------------------------------------------------
107 ScDPCacheTable::SingleFilter::SingleFilter(ScSimpleSharedString& rSharedString,
108 sal_Int32 nMatchStrId, double fValue, bool bHasValue) :
109 mrSharedString(rSharedString)
111 maItem.mnMatchStrId = nMatchStrId;
112 maItem.mfValue = fValue;
113 maItem.mbHasValue = bHasValue;
116 bool ScDPCacheTable::SingleFilter::match(const ScDPCacheCell& rCell) const
118 if (rCell.mnStrId != maItem.mnMatchStrId &&
119 (!rCell.mbNumeric || rCell.mfValue != maItem.mfValue))
120 return false;
122 return true;
125 const String ScDPCacheTable::SingleFilter::getMatchString()
127 const String* pStr = mrSharedString.getString(maItem.mnMatchStrId);
128 if (pStr)
129 return *pStr;
131 return String();
134 double ScDPCacheTable::SingleFilter::getMatchValue() const
136 return maItem.mfValue;
139 bool ScDPCacheTable::SingleFilter::hasValue() const
141 return maItem.mbHasValue;
144 // ----------------------------------------------------------------------------
146 ScDPCacheTable::GroupFilter::GroupFilter(ScSimpleSharedString& rSharedString) :
147 mrSharedString(rSharedString)
151 bool ScDPCacheTable::GroupFilter::match(const ScDPCacheCell& rCell) const
153 vector<FilterItem>::const_iterator itrEnd = maItems.end();
154 for (vector<FilterItem>::const_iterator itr = maItems.begin(); itr != itrEnd; ++itr)
156 bool bMatch = false;
157 if (rCell.mbNumeric)
158 bMatch = (itr->mfValue == rCell.mfValue);
159 else
160 bMatch = (itr->mnMatchStrId == rCell.mnStrId);
162 if (bMatch)
163 return true;
165 return false;
168 void ScDPCacheTable::GroupFilter::addMatchItem(const String& rStr, double fVal, bool bHasValue)
170 sal_Int32 nStrId = mrSharedString.getStringId(rStr);
171 FilterItem aItem;
172 aItem.mnMatchStrId = nStrId;
173 aItem.mfValue = fVal;
174 aItem.mbHasValue = bHasValue;
175 maItems.push_back(aItem);
178 size_t ScDPCacheTable::GroupFilter::getMatchItemCount() const
180 return maItems.size();
183 // ----------------------------------------------------------------------------
185 ScDPCacheTable::Criterion::Criterion() :
186 mnFieldIndex(-1),
187 mpFilter(static_cast<FilterBase*>(NULL))
191 // ----------------------------------------------------------------------------
193 ScDPCacheTable::ScDPCacheTable(ScDPCollection* pCollection) :
194 mrSharedString(pCollection->GetSharedString()),
195 mpCollection(pCollection)
199 ScDPCacheTable::~ScDPCacheTable()
203 sal_Int32 ScDPCacheTable::getRowSize() const
205 return maTable.size();
208 sal_Int32 ScDPCacheTable::getColSize() const
210 return maTable.empty() ? 0 : maTable[0].size();
213 namespace {
215 /**
216 * While the macro interpret level is incremented, the formula cells are
217 * (semi-)guaranteed to be interpreted.
219 class MacroInterpretIncrementer
221 public:
222 MacroInterpretIncrementer(ScDocument* pDoc) :
223 mpDoc(pDoc)
225 mpDoc->IncMacroInterpretLevel();
227 ~MacroInterpretIncrementer()
229 mpDoc->DecMacroInterpretLevel();
231 private:
232 ScDocument* mpDoc;
237 void ScDPCacheTable::fillTable(ScDocument* pDoc, const ScRange& rRange, const ScQueryParam& rQuery, BOOL* pSpecial,
238 bool bIgnoreEmptyRows)
240 // Make sure the formula cells within the data range are interpreted
241 // during this call, for this method may be called from the interpretation
242 // of GETPIVOTDATA, which disables nested formula interpretation without
243 // an increased macro level.
244 MacroInterpretIncrementer aMacroInc(pDoc);
246 SCTAB nTab = rRange.aStart.Tab();
247 SCCOL nStartCol = rRange.aStart.Col();
248 SCROW nStartRow = rRange.aStart.Row();
249 SCCOL nColCount = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
250 SCROW nRowCount = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
252 if (nRowCount <= 1 || nColCount <= 0)
253 return;
255 maTable.clear();
256 maTable.reserve(nRowCount);
257 maHeader.clear();
258 maHeader.reserve(nColCount);
259 maRowsVisible.clear();
260 maRowsVisible.reserve(nRowCount);
262 // Header row
263 for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
265 String aStr;
266 pDoc->GetString(nCol + nStartCol, nStartRow, nTab, aStr);
267 sal_Int32 nStrId = mrSharedString.insertString(aStr);
268 maHeader.push_back(nStrId);
271 // Initialize field entries container.
272 maFieldEntries.clear();
273 maFieldEntries.reserve(nColCount);
274 for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
276 TypedScStrCollectionPtr p(new TypedScStrCollection);
277 maFieldEntries.push_back(p);
280 vector<SCROW> aLastNonEmptyRows(nColCount, 0);
282 // Data rows
283 for (SCROW nRow = 1; nRow < nRowCount; ++nRow)
285 if ( lcl_HasQueryEntry(rQuery) && !pDoc->ValidQuery(nRow + nStartRow, nTab, rQuery, pSpecial) )
286 // filtered out by standard filter.
287 continue;
289 if ( bIgnoreEmptyRows &&
290 pDoc->IsBlockEmpty(nTab, nStartCol, nRow + nStartRow,
291 nStartCol + nColCount - 1, nRow + nStartRow) )
292 // skip an empty row.
293 continue;
295 // Insert a new row into cache table.
296 maRowsVisible.push_back(true);
297 maTable.push_back( vector<Cell>() );
298 maTable.back().reserve(nColCount);
300 for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
302 maTable.back().push_back( ScDPCacheTable::Cell() );
303 Cell& rCell = maTable.back().back();
304 rCell.mnCategoryRef = maTable.size()-1;
306 String aCellStr;
307 bool bReadCell = nRow == 0 || pDoc->HasData(nStartCol + nCol, nStartRow + nRow, nTab);
308 if (bReadCell)
310 aLastNonEmptyRows[nCol] = maTable.size()-1;
311 ScDPCacheCell aCell;
312 pDoc->GetString(nStartCol + nCol, nStartRow + nRow, nTab, aCellStr);
313 aCell.mnStrId = mrSharedString.insertString(aCellStr);
314 aCell.mnType = SC_VALTYPE_STRING;
315 aCell.mbNumeric = false;
316 ScAddress aPos(nStartCol + nCol, nStartRow + nRow, nTab);
317 getValueData(pDoc, aPos, aCell);
318 rCell.mpContent = mpCollection->getCacheCellFromPool(aCell);
320 else
321 rCell.mnCategoryRef = aLastNonEmptyRows[nCol];
323 TypedStrData* pNew;
324 if (rCell.mpContent && rCell.mpContent->mbNumeric)
325 pNew = new TypedStrData(aCellStr, rCell.mpContent->mfValue, SC_STRTYPE_VALUE);
326 else
327 pNew = new TypedStrData(aCellStr);
329 if (!maFieldEntries[nCol]->Insert(pNew))
330 delete pNew;
335 void lcl_GetCellValue(const Reference<sdbc::XRow>& xRow, sal_Int32 nType, long nCol,
336 const Date& rNullDate, ScDPCacheCell& rCell, String& rStr,
337 ScSimpleSharedString& rSharedString)
339 short nNumType = NUMBERFORMAT_NUMBER;
340 BOOL bEmptyFlag = FALSE;
343 rStr = xRow->getString(nCol);
344 rCell.mnStrId = rSharedString.getStringId(rStr);
345 rCell.mnType = SC_VALTYPE_STRING;
347 switch (nType)
349 case sdbc::DataType::BIT:
350 case sdbc::DataType::BOOLEAN:
352 nNumType = NUMBERFORMAT_LOGICAL;
353 rCell.mfValue = xRow->getBoolean(nCol) ? 1 : 0;
354 bEmptyFlag = (rCell.mfValue == 0.0 && xRow->wasNull());
355 rCell.mbNumeric = true;
356 rCell.mnType = SC_VALTYPE_VALUE;
358 break;
360 case sdbc::DataType::TINYINT:
361 case sdbc::DataType::SMALLINT:
362 case sdbc::DataType::INTEGER:
363 case sdbc::DataType::BIGINT:
364 case sdbc::DataType::FLOAT:
365 case sdbc::DataType::REAL:
366 case sdbc::DataType::DOUBLE:
367 case sdbc::DataType::NUMERIC:
368 case sdbc::DataType::DECIMAL:
370 //! do the conversion here?
371 rCell.mfValue = xRow->getDouble(nCol);
372 bEmptyFlag = (rCell.mfValue == 0.0 && xRow->wasNull());
373 rCell.mbNumeric = true;
374 rCell.mnType = SC_VALTYPE_VALUE;
376 break;
378 case sdbc::DataType::CHAR:
379 case sdbc::DataType::VARCHAR:
380 case sdbc::DataType::LONGVARCHAR:
381 bEmptyFlag = (rStr.Len() == 0 && xRow->wasNull());
382 break;
384 case sdbc::DataType::DATE:
386 nNumType = NUMBERFORMAT_DATE;
388 util::Date aDate = xRow->getDate(nCol);
389 rCell.mfValue = Date(aDate.Day, aDate.Month, aDate.Year) - rNullDate;
390 bEmptyFlag = xRow->wasNull();
391 rCell.mbNumeric = true;
392 rCell.mnType = SC_VALTYPE_VALUE;
394 break;
396 case sdbc::DataType::TIME:
398 nNumType = NUMBERFORMAT_TIME;
400 util::Time aTime = xRow->getTime(nCol);
401 rCell.mfValue = ( aTime.Hours * 3600 + aTime.Minutes * 60 +
402 aTime.Seconds + aTime.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
403 bEmptyFlag = xRow->wasNull();
404 rCell.mbNumeric = true;
405 rCell.mnType = SC_VALTYPE_VALUE;
407 break;
409 case sdbc::DataType::TIMESTAMP:
411 nNumType = NUMBERFORMAT_DATETIME;
413 util::DateTime aStamp = xRow->getTimestamp(nCol);
414 rCell.mfValue = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) - rNullDate ) +
415 ( aStamp.Hours * 3600 + aStamp.Minutes * 60 +
416 aStamp.Seconds + aStamp.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
417 bEmptyFlag = xRow->wasNull();
418 rCell.mbNumeric = true;
419 rCell.mnType = SC_VALTYPE_VALUE;
421 break;
423 case sdbc::DataType::SQLNULL:
424 case sdbc::DataType::BINARY:
425 case sdbc::DataType::VARBINARY:
426 case sdbc::DataType::LONGVARBINARY:
427 default:
428 break;
431 catch (uno::Exception&)
436 void ScDPCacheTable::fillTable(const Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate)
438 if (!xRowSet.is())
439 // Dont' even waste time to go any further.
440 return;
444 Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(xRowSet, UNO_QUERY_THROW);
445 Reference<sdbc::XResultSetMetaData> xMeta = xMetaSupp->getMetaData();
446 if (!xMeta.is())
447 return;
449 sal_Int32 nColCount = xMeta->getColumnCount();
451 // Get column titles and types.
452 vector<sal_Int32> aColTypes(nColCount);
453 maHeader.clear();
454 maHeader.reserve(nColCount);
455 for (sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
457 String aColTitle = xMeta->getColumnLabel(nCol+1);
458 aColTypes[nCol] = xMeta->getColumnType(nCol+1);
459 maHeader.push_back( mrSharedString.getStringId(aColTitle) );
462 // Initialize field entries container.
463 maFieldEntries.clear();
464 maFieldEntries.reserve(nColCount);
465 for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
467 TypedScStrCollectionPtr p(new TypedScStrCollection);
468 maFieldEntries.push_back(p);
471 // Now get the data rows.
472 Reference<sdbc::XRow> xRow(xRowSet, UNO_QUERY_THROW);
473 xRowSet->first();
474 maTable.clear();
475 maRowsVisible.clear();
478 maRowsVisible.push_back(true);
479 maTable.push_back( vector<Cell>() );
480 maTable.back().reserve(nColCount);
481 for (sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
483 maTable.back().push_back( Cell() );
484 Cell& rCell = maTable.back().back();
485 ScDPCacheCell aCellContent;
486 String aStr;
487 lcl_GetCellValue(xRow, aColTypes[nCol], nCol+1, rNullDate, aCellContent, aStr, mrSharedString);
488 rCell.mpContent = mpCollection->getCacheCellFromPool(aCellContent);
490 TypedStrData* pNew;
491 if (rCell.mpContent->mbNumeric)
492 pNew = new TypedStrData(aStr, rCell.mpContent->mfValue, SC_STRTYPE_VALUE);
493 else
494 pNew = new TypedStrData(aStr);
496 if (!maFieldEntries[nCol]->Insert(pNew))
497 delete pNew;
500 while (xRowSet->next());
502 xRowSet->beforeFirst();
504 catch (const Exception&)
509 bool ScDPCacheTable::isRowActive(sal_Int32 nRow) const
511 if (nRow < 0 || static_cast<size_t>(nRow) >= maRowsVisible.size())
512 // row index out of bound
513 return false;
515 return maRowsVisible[nRow];
518 void ScDPCacheTable::filterByPageDimension(const vector<Criterion>& rCriteria, const hash_set<sal_Int32>& rRepeatIfEmptyDims)
520 sal_Int32 nRowSize = getRowSize();
521 if (nRowSize != static_cast<sal_Int32>(maRowsVisible.size()))
523 // sizes of the two tables differ!
524 return;
527 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
528 maRowsVisible[nRow] = isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims);
531 const ScDPCacheCell* ScDPCacheTable::getCell(SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
533 if ( nRow >= static_cast<SCROW>(maTable.size()) )
534 return NULL;
536 const vector<Cell>& rRow = maTable[nRow];
537 if ( nCol < 0 || static_cast<size_t>(nCol) >= rRow.size() )
538 return NULL;
540 const Cell& rCell = rRow[nCol];
541 const ScDPCacheCell* pCell = rCell.mpContent;
542 if (bRepeatIfEmpty && !pCell)
543 pCell = getCell(nCol, rCell.mnCategoryRef, false);
545 return pCell ? pCell : &EmptyCellContent;
548 const String* ScDPCacheTable::getFieldName(sal_Int32 nIndex) const
550 if (nIndex >= static_cast<sal_Int32>(maHeader.size()))
551 return NULL;
553 return mrSharedString.getString(maHeader[nIndex]);
556 const TypedScStrCollection& ScDPCacheTable::getFieldEntries(sal_Int32 nIndex) const
558 if (nIndex < 0 || static_cast<size_t>(nIndex) >= maFieldEntries.size())
560 // index out of bound. Hopefully this code will never be reached.
561 static const TypedScStrCollection emptyCollection;
562 return emptyCollection;
565 return *maFieldEntries[nIndex].get();
568 void ScDPCacheTable::filterTable(const vector<Criterion>& rCriteria, Sequence< Sequence<Any> >& rTabData,
569 const hash_set<sal_Int32>& rRepeatIfEmptyDims)
571 sal_Int32 nRowSize = getRowSize();
572 sal_Int32 nColSize = getColSize();
574 if (!nRowSize)
575 // no data to filter.
576 return;
578 // Row first, then column.
579 vector< Sequence<Any> > tableData;
580 tableData.reserve(nRowSize+1);
582 // Header first.
583 Sequence<Any> headerRow(nColSize);
584 for (sal_Int32 nCol = 0; nCol < nColSize; ++nCol)
586 OUString str;
587 const String* pStr = mrSharedString.getString(maHeader[nCol]);
588 if (pStr)
589 str = *pStr;
591 Any any;
592 any <<= str;
593 headerRow[nCol] = any;
595 tableData.push_back(headerRow);
598 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
600 if (!maRowsVisible[nRow])
601 // This row is filtered out.
602 continue;
604 if (!isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims))
605 continue;
607 // Insert this row into table.
609 Sequence<Any> row(nColSize);
610 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
612 Any any;
613 bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(nCol) > 0;
614 const ScDPCacheCell* pCell = getCell(nCol, nRow, bRepeatIfEmpty);
615 if (!pCell)
617 // This should never happen, but in case this happens, just
618 // stick in an empty string.
619 OUString str;
620 any <<= str;
621 row[nCol] = any;
622 continue;
625 if (pCell->mbNumeric)
626 any <<= pCell->mfValue;
627 else
629 OUString str;
630 const String* pStr = mrSharedString.getString(pCell->mnStrId);
631 if (pStr)
632 str = *pStr;
633 any <<= str;
635 row[nCol] = any;
637 tableData.push_back(row);
640 // convert vector to Seqeunce
641 sal_Int32 nTabSize = static_cast<sal_Int32>(tableData.size());
642 rTabData.realloc(nTabSize);
643 for (sal_Int32 i = 0; i < nTabSize; ++i)
644 rTabData[i] = tableData[i];
647 void ScDPCacheTable::clear()
649 maTable.clear();
650 maHeader.clear();
651 maFieldEntries.clear();
652 maRowsVisible.clear();
655 bool ScDPCacheTable::empty() const
657 return maTable.empty();
660 bool ScDPCacheTable::isRowQualified(sal_Int32 nRow, const vector<Criterion>& rCriteria,
661 const hash_set<sal_Int32>& rRepeatIfEmptyDims) const
663 sal_Int32 nColSize = getColSize();
664 vector<Criterion>::const_iterator itrEnd = rCriteria.end();
665 for (vector<Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
667 if (itr->mnFieldIndex >= nColSize)
668 // specified field is outside the source data columns. Don't
669 // use this criterion.
670 continue;
672 // Check if the 'repeat if empty' flag is set for this field.
673 bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(itr->mnFieldIndex) > 0;
674 const ScDPCacheCell* pCell = getCell(static_cast<SCCOL>(itr->mnFieldIndex), nRow, bRepeatIfEmpty);
675 if (!pCell)
676 // This should never happen, but just in case...
677 return false;
679 if (!itr->mpFilter->match(*pCell))
680 return false;
682 return true;
685 void ScDPCacheTable::getValueData(ScDocument* pDoc, const ScAddress& rPos, ScDPCacheCell& rCell)
687 ScBaseCell* pCell = pDoc->GetCell(rPos);
688 if (!pCell)
690 rCell.mnType = SC_VALTYPE_EMPTY;
691 return;
694 CellType eType = pCell->GetCellType();
695 if (eType == CELLTYPE_NOTE)
697 // note cell
698 rCell.mnType = SC_VALTYPE_EMPTY;
699 return;
702 if (eType == CELLTYPE_FORMULA && static_cast<ScFormulaCell*>(pCell)->GetErrCode())
704 // formula cell with error
705 rCell.mnType = SC_VALTYPE_ERROR;
706 return;
709 if ( pCell->HasValueData() )
711 if (eType == CELLTYPE_VALUE)
712 // value cell
713 rCell.mfValue = static_cast<ScValueCell*>(pCell)->GetValue();
714 else if (eType == CELLTYPE_FORMULA)
715 // formula cell
716 rCell.mfValue = static_cast<ScFormulaCell*>(pCell)->GetValue();
718 rCell.mbNumeric = true;
719 rCell.mnType = SC_VALTYPE_VALUE;