Update to m13
[ooovba.git] / sc / source / core / data / dpcachetable.cxx
bloba27c16d9eefea5e245b2bb128eae574fa3cf0c23
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"
42 #include <com/sun/star/i18n/LocaleDataItem.hpp>
43 #include <com/sun/star/sdbc/DataType.hpp>
44 #include <com/sun/star/sdbc/XRow.hpp>
45 #include <com/sun/star/sdbc/XRowSet.hpp>
46 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
47 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
48 #include <com/sun/star/util/Date.hpp>
49 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
50 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
52 #include <memory>
54 using namespace ::com::sun::star;
56 using ::rtl::OUString;
57 using ::std::vector;
58 using ::std::pair;
59 using ::std::hash_map;
60 using ::std::hash_set;
61 using ::std::auto_ptr;
62 using ::com::sun::star::i18n::LocaleDataItem;
63 using ::com::sun::star::uno::Exception;
64 using ::com::sun::star::uno::Reference;
65 using ::com::sun::star::uno::Sequence;
66 using ::com::sun::star::uno::Any;
67 using ::com::sun::star::uno::UNO_QUERY;
68 using ::com::sun::star::uno::UNO_QUERY_THROW;
69 using ::com::sun::star::sheet::DataPilotFieldFilter;
71 const double D_TIMEFACTOR = 86400.0;
73 static BOOL lcl_HasQueryEntry( const ScQueryParam& rParam )
75 return rParam.GetEntryCount() > 0 &&
76 rParam.GetEntry(0).bDoQuery;
79 // ----------------------------------------------------------------------------
81 static ScDPCacheCell EmptyCellContent = ScDPCacheCell();
83 // ----------------------------------------------------------------------------
85 ScDPCacheTable::Cell::Cell() :
86 mnCategoryRef(0),
87 mpContent(NULL)
91 ScDPCacheTable::Cell::~Cell()
95 // ----------------------------------------------------------------------------
97 ScDPCacheTable::FilterItem::FilterItem() :
98 mnMatchStrId(ScSimpleSharedString::EMPTY),
99 mfValue(0.0),
100 mbHasValue(false)
104 // ----------------------------------------------------------------------------
106 ScDPCacheTable::SingleFilter::SingleFilter(ScSimpleSharedString& rSharedString,
107 sal_Int32 nMatchStrId, double fValue, bool bHasValue) :
108 mrSharedString(rSharedString)
110 maItem.mnMatchStrId = nMatchStrId;
111 maItem.mfValue = fValue;
112 maItem.mbHasValue = bHasValue;
115 bool ScDPCacheTable::SingleFilter::match(const ScDPCacheCell& rCell) const
117 if (rCell.mnStrId != maItem.mnMatchStrId &&
118 (!rCell.mbNumeric || rCell.mfValue != maItem.mfValue))
119 return false;
121 return true;
124 const String ScDPCacheTable::SingleFilter::getMatchString()
126 const String* pStr = mrSharedString.getString(maItem.mnMatchStrId);
127 if (pStr)
128 return *pStr;
130 return String();
133 double ScDPCacheTable::SingleFilter::getMatchValue() const
135 return maItem.mfValue;
138 bool ScDPCacheTable::SingleFilter::hasValue() const
140 return maItem.mbHasValue;
143 // ----------------------------------------------------------------------------
145 ScDPCacheTable::GroupFilter::GroupFilter(ScSimpleSharedString& rSharedString) :
146 mrSharedString(rSharedString)
150 bool ScDPCacheTable::GroupFilter::match(const ScDPCacheCell& rCell) const
152 vector<FilterItem>::const_iterator itrEnd = maItems.end();
153 for (vector<FilterItem>::const_iterator itr = maItems.begin(); itr != itrEnd; ++itr)
155 bool bMatch = false;
156 if (rCell.mbNumeric)
157 bMatch = (itr->mfValue == rCell.mfValue);
158 else
159 bMatch = (itr->mnMatchStrId == rCell.mnStrId);
161 if (bMatch)
162 return true;
164 return false;
167 void ScDPCacheTable::GroupFilter::addMatchItem(const String& rStr, double fVal, bool bHasValue)
169 sal_Int32 nStrId = mrSharedString.getStringId(rStr);
170 FilterItem aItem;
171 aItem.mnMatchStrId = nStrId;
172 aItem.mfValue = fVal;
173 aItem.mbHasValue = bHasValue;
174 maItems.push_back(aItem);
177 size_t ScDPCacheTable::GroupFilter::getMatchItemCount() const
179 return maItems.size();
182 // ----------------------------------------------------------------------------
184 ScDPCacheTable::Criterion::Criterion() :
185 mnFieldIndex(-1),
186 mpFilter(static_cast<FilterBase*>(NULL))
190 // ----------------------------------------------------------------------------
192 ScDPCacheTable::ScDPCacheTable(ScDPCollection* pCollection) :
193 mrSharedString(pCollection->GetSharedString()),
194 mpCollection(pCollection)
198 ScDPCacheTable::~ScDPCacheTable()
202 sal_Int32 ScDPCacheTable::getRowSize() const
204 return maTable.size();
207 sal_Int32 ScDPCacheTable::getColSize() const
209 return maTable.empty() ? 0 : maTable[0].size();
212 void ScDPCacheTable::fillTable(ScDocument* pDoc, const ScRange& rRange, const ScQueryParam& rQuery, BOOL* pSpecial,
213 bool bIgnoreEmptyRows)
215 SCTAB nTab = rRange.aStart.Tab();
216 SCCOL nStartCol = rRange.aStart.Col();
217 SCROW nStartRow = rRange.aStart.Row();
218 SCCOL nColCount = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
219 SCROW nRowCount = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
221 if (nRowCount <= 1 || nColCount <= 0)
222 return;
224 maTable.clear();
225 maTable.reserve(nRowCount);
226 maHeader.clear();
227 maHeader.reserve(nColCount);
228 maRowsVisible.clear();
229 maRowsVisible.reserve(nRowCount);
231 // Header row
232 for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
234 String aStr;
235 pDoc->GetString(nCol + nStartCol, nStartRow, nTab, aStr);
236 sal_Int32 nStrId = mrSharedString.insertString(aStr);
237 maHeader.push_back(nStrId);
240 // Initialize field entries container.
241 maFieldEntries.clear();
242 maFieldEntries.reserve(nColCount);
243 for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
245 TypedScStrCollectionPtr p(new TypedScStrCollection);
246 maFieldEntries.push_back(p);
249 vector<SCROW> aLastNonEmptyRows(nColCount, 0);
251 // Data rows
252 for (SCROW nRow = 1; nRow < nRowCount; ++nRow)
254 if ( lcl_HasQueryEntry(rQuery) && !pDoc->ValidQuery(nRow + nStartRow, nTab, rQuery, pSpecial) )
255 // filtered out by standard filter.
256 continue;
258 if ( bIgnoreEmptyRows &&
259 pDoc->IsBlockEmpty(nTab, nStartCol, nRow + nStartRow,
260 nStartCol + nColCount - 1, nRow + nStartRow) )
261 // skip an empty row.
262 continue;
264 // Insert a new row into cache table.
265 maRowsVisible.push_back(true);
266 maTable.push_back( vector<Cell>() );
267 maTable.back().reserve(nColCount);
269 for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
271 maTable.back().push_back( ScDPCacheTable::Cell() );
272 Cell& rCell = maTable.back().back();
273 rCell.mnCategoryRef = maTable.size()-1;
275 String aCellStr;
276 bool bReadCell = nRow == 0 || pDoc->HasData(nStartCol + nCol, nStartRow + nRow, nTab);
277 if (bReadCell)
279 aLastNonEmptyRows[nCol] = maTable.size()-1;
280 ScDPCacheCell aCell;
281 pDoc->GetString(nStartCol + nCol, nStartRow + nRow, nTab, aCellStr);
282 aCell.mnStrId = mrSharedString.insertString(aCellStr);
283 aCell.mnType = SC_VALTYPE_STRING;
284 aCell.mbNumeric = false;
285 ScAddress aPos(nStartCol + nCol, nStartRow + nRow, nTab);
286 getValueData(pDoc, aPos, aCell);
287 rCell.mpContent = mpCollection->getCacheCellFromPool(aCell);
289 else
290 rCell.mnCategoryRef = aLastNonEmptyRows[nCol];
292 TypedStrData* pNew;
293 if (rCell.mpContent && rCell.mpContent->mbNumeric)
294 pNew = new TypedStrData(aCellStr, rCell.mpContent->mfValue, SC_STRTYPE_VALUE);
295 else
296 pNew = new TypedStrData(aCellStr);
298 if (!maFieldEntries[nCol]->Insert(pNew))
299 delete pNew;
304 void lcl_GetCellValue(const Reference<sdbc::XRow>& xRow, sal_Int32 nType, long nCol,
305 const Date& rNullDate, ScDPCacheCell& rCell, String& rStr,
306 ScSimpleSharedString& rSharedString)
308 short nNumType = NUMBERFORMAT_NUMBER;
309 BOOL bEmptyFlag = FALSE;
312 rStr = xRow->getString(nCol);
313 rCell.mnStrId = rSharedString.getStringId(rStr);
314 rCell.mnType = SC_VALTYPE_STRING;
316 switch (nType)
318 case sdbc::DataType::BIT:
319 case sdbc::DataType::BOOLEAN:
321 nNumType = NUMBERFORMAT_LOGICAL;
322 rCell.mfValue = xRow->getBoolean(nCol) ? 1 : 0;
323 bEmptyFlag = (rCell.mfValue == 0.0 && xRow->wasNull());
324 rCell.mbNumeric = true;
325 rCell.mnType = SC_VALTYPE_VALUE;
327 break;
329 case sdbc::DataType::TINYINT:
330 case sdbc::DataType::SMALLINT:
331 case sdbc::DataType::INTEGER:
332 case sdbc::DataType::BIGINT:
333 case sdbc::DataType::FLOAT:
334 case sdbc::DataType::REAL:
335 case sdbc::DataType::DOUBLE:
336 case sdbc::DataType::NUMERIC:
337 case sdbc::DataType::DECIMAL:
339 //! do the conversion here?
340 rCell.mfValue = xRow->getDouble(nCol);
341 bEmptyFlag = (rCell.mfValue == 0.0 && xRow->wasNull());
342 rCell.mbNumeric = true;
343 rCell.mnType = SC_VALTYPE_VALUE;
345 break;
347 case sdbc::DataType::CHAR:
348 case sdbc::DataType::VARCHAR:
349 case sdbc::DataType::LONGVARCHAR:
350 bEmptyFlag = (rStr.Len() == 0 && xRow->wasNull());
351 break;
353 case sdbc::DataType::DATE:
355 nNumType = NUMBERFORMAT_DATE;
357 util::Date aDate = xRow->getDate(nCol);
358 rCell.mfValue = Date(aDate.Day, aDate.Month, aDate.Year) - rNullDate;
359 bEmptyFlag = xRow->wasNull();
360 rCell.mbNumeric = true;
361 rCell.mnType = SC_VALTYPE_VALUE;
363 break;
365 case sdbc::DataType::TIME:
367 nNumType = NUMBERFORMAT_TIME;
369 util::Time aTime = xRow->getTime(nCol);
370 rCell.mfValue = ( aTime.Hours * 3600 + aTime.Minutes * 60 +
371 aTime.Seconds + aTime.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
372 bEmptyFlag = xRow->wasNull();
373 rCell.mbNumeric = true;
374 rCell.mnType = SC_VALTYPE_VALUE;
376 break;
378 case sdbc::DataType::TIMESTAMP:
380 nNumType = NUMBERFORMAT_DATETIME;
382 util::DateTime aStamp = xRow->getTimestamp(nCol);
383 rCell.mfValue = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) - rNullDate ) +
384 ( aStamp.Hours * 3600 + aStamp.Minutes * 60 +
385 aStamp.Seconds + aStamp.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
386 bEmptyFlag = xRow->wasNull();
387 rCell.mbNumeric = true;
388 rCell.mnType = SC_VALTYPE_VALUE;
390 break;
392 case sdbc::DataType::SQLNULL:
393 case sdbc::DataType::BINARY:
394 case sdbc::DataType::VARBINARY:
395 case sdbc::DataType::LONGVARBINARY:
396 default:
397 break;
400 catch (uno::Exception&)
405 void ScDPCacheTable::fillTable(const Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate)
407 if (!xRowSet.is())
408 // Dont' even waste time to go any further.
409 return;
413 Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(xRowSet, UNO_QUERY_THROW);
414 Reference<sdbc::XResultSetMetaData> xMeta = xMetaSupp->getMetaData();
415 if (!xMeta.is())
416 return;
418 sal_Int32 nColCount = xMeta->getColumnCount();
420 // Get column titles and types.
421 vector<sal_Int32> aColTypes(nColCount);
422 maHeader.clear();
423 maHeader.reserve(nColCount);
424 for (sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
426 String aColTitle = xMeta->getColumnLabel(nCol+1);
427 aColTypes[nCol] = xMeta->getColumnType(nCol+1);
428 maHeader.push_back( mrSharedString.getStringId(aColTitle) );
431 // Initialize field entries container.
432 maFieldEntries.clear();
433 maFieldEntries.reserve(nColCount);
434 for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
436 TypedScStrCollectionPtr p(new TypedScStrCollection);
437 maFieldEntries.push_back(p);
440 // Now get the data rows.
441 Reference<sdbc::XRow> xRow(xRowSet, UNO_QUERY_THROW);
442 xRowSet->first();
443 maTable.clear();
444 maRowsVisible.clear();
447 maRowsVisible.push_back(true);
448 maTable.push_back( vector<Cell>() );
449 maTable.back().reserve(nColCount);
450 for (sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
452 maTable.back().push_back( Cell() );
453 Cell& rCell = maTable.back().back();
454 ScDPCacheCell aCellContent;
455 String aStr;
456 lcl_GetCellValue(xRow, aColTypes[nCol], nCol+1, rNullDate, aCellContent, aStr, mrSharedString);
457 rCell.mpContent = mpCollection->getCacheCellFromPool(aCellContent);
459 TypedStrData* pNew;
460 if (rCell.mpContent->mbNumeric)
461 pNew = new TypedStrData(aStr, rCell.mpContent->mfValue, SC_STRTYPE_VALUE);
462 else
463 pNew = new TypedStrData(aStr);
465 if (!maFieldEntries[nCol]->Insert(pNew))
466 delete pNew;
469 while (xRowSet->next());
471 xRowSet->beforeFirst();
473 catch (const Exception&)
478 bool ScDPCacheTable::isRowActive(sal_Int32 nRow) const
480 if (nRow < 0 || static_cast<size_t>(nRow) >= maRowsVisible.size())
481 // row index out of bound
482 return false;
484 return maRowsVisible[nRow];
487 void ScDPCacheTable::filterByPageDimension(const vector<Criterion>& rCriteria, const hash_set<sal_Int32>& rRepeatIfEmptyDims)
489 sal_Int32 nRowSize = getRowSize();
490 if (nRowSize != static_cast<sal_Int32>(maRowsVisible.size()))
492 // sizes of the two tables differ!
493 return;
496 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
497 maRowsVisible[nRow] = isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims);
500 const ScDPCacheCell* ScDPCacheTable::getCell(SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
502 if ( nRow >= static_cast<SCROW>(maTable.size()) )
503 return NULL;
505 const vector<Cell>& rRow = maTable[nRow];
506 if ( nCol < 0 || static_cast<size_t>(nCol) >= rRow.size() )
507 return NULL;
509 const Cell& rCell = rRow[nCol];
510 const ScDPCacheCell* pCell = rCell.mpContent;
511 if (bRepeatIfEmpty && !pCell)
512 pCell = getCell(nCol, rCell.mnCategoryRef, false);
514 return pCell ? pCell : &EmptyCellContent;
517 const String* ScDPCacheTable::getFieldName(sal_Int32 nIndex) const
519 if (nIndex >= static_cast<sal_Int32>(maHeader.size()))
520 return NULL;
522 return mrSharedString.getString(maHeader[nIndex]);
525 sal_Int32 ScDPCacheTable::getFieldIndex(const String& rStr) const
527 sal_Int32 nStrId = mrSharedString.getStringId(rStr);
528 if (nStrId < 0)
529 // string not found.
530 return nStrId;
532 sal_Int32 n = maHeader.size();
533 for (sal_Int32 i = 0; i < n; ++i)
535 if (maHeader[i] == nStrId)
536 return i;
539 return -1;
542 const TypedScStrCollection& ScDPCacheTable::getFieldEntries(sal_Int32 nIndex) const
544 if (nIndex < 0 || static_cast<size_t>(nIndex) >= maFieldEntries.size())
546 // index out of bound. Hopefully this code will never be reached.
547 static const TypedScStrCollection emptyCollection;
548 return emptyCollection;
551 return *maFieldEntries[nIndex].get();
554 void ScDPCacheTable::filterTable(const vector<Criterion>& rCriteria, Sequence< Sequence<Any> >& rTabData,
555 const hash_set<sal_Int32>& rRepeatIfEmptyDims)
557 sal_Int32 nRowSize = getRowSize();
558 sal_Int32 nColSize = getColSize();
560 if (!nRowSize)
561 // no data to filter.
562 return;
564 // Row first, then column.
565 vector< Sequence<Any> > tableData;
566 tableData.reserve(nRowSize+1);
568 // Header first.
569 Sequence<Any> headerRow(nColSize);
570 for (sal_Int32 nCol = 0; nCol < nColSize; ++nCol)
572 OUString str;
573 const String* pStr = mrSharedString.getString(maHeader[nCol]);
574 if (pStr)
575 str = *pStr;
577 Any any;
578 any <<= str;
579 headerRow[nCol] = any;
581 tableData.push_back(headerRow);
584 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
586 if (!maRowsVisible[nRow])
587 // This row is filtered out.
588 continue;
590 if (!isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims))
591 continue;
593 // Insert this row into table.
595 Sequence<Any> row(nColSize);
596 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
598 Any any;
599 bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(nCol) > 0;
600 const ScDPCacheCell* pCell = getCell(nCol, nRow, bRepeatIfEmpty);
601 if (!pCell)
603 // This should never happen, but in case this happens, just
604 // stick in an empty string.
605 OUString str;
606 any <<= str;
607 row[nCol] = any;
608 continue;
611 if (pCell->mbNumeric)
612 any <<= pCell->mfValue;
613 else
615 OUString str;
616 const String* pStr = mrSharedString.getString(pCell->mnStrId);
617 if (pStr)
618 str = *pStr;
619 any <<= str;
621 row[nCol] = any;
623 tableData.push_back(row);
626 // convert vector to Seqeunce
627 sal_Int32 nTabSize = static_cast<sal_Int32>(tableData.size());
628 rTabData.realloc(nTabSize);
629 for (sal_Int32 i = 0; i < nTabSize; ++i)
630 rTabData[i] = tableData[i];
633 void ScDPCacheTable::clear()
635 maTable.clear();
636 maHeader.clear();
637 maFieldEntries.clear();
638 maRowsVisible.clear();
641 void ScDPCacheTable::swap(ScDPCacheTable& rOther)
643 maTable.swap(rOther.maTable);
644 maHeader.swap(rOther.maHeader);
645 maFieldEntries.swap(rOther.maFieldEntries);
646 maRowsVisible.swap(rOther.maRowsVisible);
649 bool ScDPCacheTable::empty() const
651 return maTable.empty();
654 bool ScDPCacheTable::isRowQualified(sal_Int32 nRow, const vector<Criterion>& rCriteria,
655 const hash_set<sal_Int32>& rRepeatIfEmptyDims) const
657 sal_Int32 nColSize = getColSize();
658 vector<Criterion>::const_iterator itrEnd = rCriteria.end();
659 for (vector<Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
661 if (itr->mnFieldIndex >= nColSize)
662 // specified field is outside the source data columns. Don't
663 // use this criterion.
664 continue;
666 // Check if the 'repeat if empty' flag is set for this field.
667 bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(itr->mnFieldIndex) > 0;
668 const ScDPCacheCell* pCell = getCell(static_cast<SCCOL>(itr->mnFieldIndex), nRow, bRepeatIfEmpty);
669 if (!pCell)
670 // This should never happen, but just in case...
671 return false;
673 if (!itr->mpFilter->match(*pCell))
674 return false;
676 return true;
679 void ScDPCacheTable::getValueData(ScDocument* pDoc, const ScAddress& rPos, ScDPCacheCell& rCell)
681 ScBaseCell* pCell = pDoc->GetCell(rPos);
682 if (!pCell)
684 rCell.mnType = SC_VALTYPE_EMPTY;
685 return;
688 CellType eType = pCell->GetCellType();
689 if (eType == CELLTYPE_NOTE)
691 // note cell
692 rCell.mnType = SC_VALTYPE_EMPTY;
693 return;
696 if (eType == CELLTYPE_FORMULA && static_cast<ScFormulaCell*>(pCell)->GetErrCode())
698 // formula cell with error
699 rCell.mnType = SC_VALTYPE_ERROR;
700 return;
703 if ( pCell->HasValueData() )
705 if (eType == CELLTYPE_VALUE)
706 // value cell
707 rCell.mfValue = static_cast<ScValueCell*>(pCell)->GetValue();
708 else if (eType == CELLTYPE_FORMULA)
709 // formula cell
710 rCell.mfValue = static_cast<ScFormulaCell*>(pCell)->GetValue();
712 rCell.mbNumeric = true;
713 rCell.mnType = SC_VALTYPE_VALUE;