update dev300-m57
[ooovba.git] / sc / source / core / data / dpcachetable.cxx
blob015c6512de2a6e065858a4467283d48f8465e398
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 const TypedScStrCollection& ScDPCacheTable::getFieldEntries(sal_Int32 nIndex) const
527 if (nIndex < 0 || static_cast<size_t>(nIndex) >= maFieldEntries.size())
529 // index out of bound. Hopefully this code will never be reached.
530 static const TypedScStrCollection emptyCollection;
531 return emptyCollection;
534 return *maFieldEntries[nIndex].get();
537 void ScDPCacheTable::filterTable(const vector<Criterion>& rCriteria, Sequence< Sequence<Any> >& rTabData,
538 const hash_set<sal_Int32>& rRepeatIfEmptyDims)
540 sal_Int32 nRowSize = getRowSize();
541 sal_Int32 nColSize = getColSize();
543 if (!nRowSize)
544 // no data to filter.
545 return;
547 // Row first, then column.
548 vector< Sequence<Any> > tableData;
549 tableData.reserve(nRowSize+1);
551 // Header first.
552 Sequence<Any> headerRow(nColSize);
553 for (sal_Int32 nCol = 0; nCol < nColSize; ++nCol)
555 OUString str;
556 const String* pStr = mrSharedString.getString(maHeader[nCol]);
557 if (pStr)
558 str = *pStr;
560 Any any;
561 any <<= str;
562 headerRow[nCol] = any;
564 tableData.push_back(headerRow);
567 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
569 if (!maRowsVisible[nRow])
570 // This row is filtered out.
571 continue;
573 if (!isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims))
574 continue;
576 // Insert this row into table.
578 Sequence<Any> row(nColSize);
579 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
581 Any any;
582 bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(nCol) > 0;
583 const ScDPCacheCell* pCell = getCell(nCol, nRow, bRepeatIfEmpty);
584 if (!pCell)
586 // This should never happen, but in case this happens, just
587 // stick in an empty string.
588 OUString str;
589 any <<= str;
590 row[nCol] = any;
591 continue;
594 if (pCell->mbNumeric)
595 any <<= pCell->mfValue;
596 else
598 OUString str;
599 const String* pStr = mrSharedString.getString(pCell->mnStrId);
600 if (pStr)
601 str = *pStr;
602 any <<= str;
604 row[nCol] = any;
606 tableData.push_back(row);
609 // convert vector to Seqeunce
610 sal_Int32 nTabSize = static_cast<sal_Int32>(tableData.size());
611 rTabData.realloc(nTabSize);
612 for (sal_Int32 i = 0; i < nTabSize; ++i)
613 rTabData[i] = tableData[i];
616 void ScDPCacheTable::clear()
618 maTable.clear();
619 maHeader.clear();
620 maFieldEntries.clear();
621 maRowsVisible.clear();
624 bool ScDPCacheTable::empty() const
626 return maTable.empty();
629 bool ScDPCacheTable::isRowQualified(sal_Int32 nRow, const vector<Criterion>& rCriteria,
630 const hash_set<sal_Int32>& rRepeatIfEmptyDims) const
632 sal_Int32 nColSize = getColSize();
633 vector<Criterion>::const_iterator itrEnd = rCriteria.end();
634 for (vector<Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
636 if (itr->mnFieldIndex >= nColSize)
637 // specified field is outside the source data columns. Don't
638 // use this criterion.
639 continue;
641 // Check if the 'repeat if empty' flag is set for this field.
642 bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(itr->mnFieldIndex) > 0;
643 const ScDPCacheCell* pCell = getCell(static_cast<SCCOL>(itr->mnFieldIndex), nRow, bRepeatIfEmpty);
644 if (!pCell)
645 // This should never happen, but just in case...
646 return false;
648 if (!itr->mpFilter->match(*pCell))
649 return false;
651 return true;
654 void ScDPCacheTable::getValueData(ScDocument* pDoc, const ScAddress& rPos, ScDPCacheCell& rCell)
656 ScBaseCell* pCell = pDoc->GetCell(rPos);
657 if (!pCell)
659 rCell.mnType = SC_VALTYPE_EMPTY;
660 return;
663 CellType eType = pCell->GetCellType();
664 if (eType == CELLTYPE_NOTE)
666 // note cell
667 rCell.mnType = SC_VALTYPE_EMPTY;
668 return;
671 if (eType == CELLTYPE_FORMULA && static_cast<ScFormulaCell*>(pCell)->GetErrCode())
673 // formula cell with error
674 rCell.mnType = SC_VALTYPE_ERROR;
675 return;
678 if ( pCell->HasValueData() )
680 if (eType == CELLTYPE_VALUE)
681 // value cell
682 rCell.mfValue = static_cast<ScValueCell*>(pCell)->GetValue();
683 else if (eType == CELLTYPE_FORMULA)
684 // formula cell
685 rCell.mfValue = static_cast<ScFormulaCell*>(pCell)->GetValue();
687 rCell.mbNumeric = true;
688 rCell.mnType = SC_VALTYPE_VALUE;