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 $
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"
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>
55 using namespace ::com::sun::star
;
57 using ::rtl::OUString
;
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() :
92 ScDPCacheTable::Cell::~Cell()
96 // ----------------------------------------------------------------------------
98 ScDPCacheTable::FilterItem::FilterItem() :
99 mnMatchStrId(ScSimpleSharedString::EMPTY
),
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
))
125 const String
ScDPCacheTable::SingleFilter::getMatchString()
127 const String
* pStr
= mrSharedString
.getString(maItem
.mnMatchStrId
);
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
)
158 bMatch
= (itr
->mfValue
== rCell
.mfValue
);
160 bMatch
= (itr
->mnMatchStrId
== rCell
.mnStrId
);
168 void ScDPCacheTable::GroupFilter::addMatchItem(const String
& rStr
, double fVal
, bool bHasValue
)
170 sal_Int32 nStrId
= mrSharedString
.getStringId(rStr
);
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() :
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();
216 * While the macro interpret level is incremented, the formula cells are
217 * (semi-)guaranteed to be interpreted.
219 class MacroInterpretIncrementer
222 MacroInterpretIncrementer(ScDocument
* pDoc
) :
225 mpDoc
->IncMacroInterpretLevel();
227 ~MacroInterpretIncrementer()
229 mpDoc
->DecMacroInterpretLevel();
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)
256 maTable
.reserve(nRowCount
);
258 maHeader
.reserve(nColCount
);
259 maRowsVisible
.clear();
260 maRowsVisible
.reserve(nRowCount
);
263 for (SCCOL nCol
= 0; nCol
< nColCount
; ++nCol
)
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);
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.
289 if ( bIgnoreEmptyRows
&&
290 pDoc
->IsBlockEmpty(nTab
, nStartCol
, nRow
+ nStartRow
,
291 nStartCol
+ nColCount
- 1, nRow
+ nStartRow
) )
292 // skip an empty row.
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;
307 bool bReadCell
= nRow
== 0 || pDoc
->HasData(nStartCol
+ nCol
, nStartRow
+ nRow
, nTab
);
310 aLastNonEmptyRows
[nCol
] = maTable
.size()-1;
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
);
321 rCell
.mnCategoryRef
= aLastNonEmptyRows
[nCol
];
324 if (rCell
.mpContent
&& rCell
.mpContent
->mbNumeric
)
325 pNew
= new TypedStrData(aCellStr
, rCell
.mpContent
->mfValue
, SC_STRTYPE_VALUE
);
327 pNew
= new TypedStrData(aCellStr
);
329 if (!maFieldEntries
[nCol
]->Insert(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
;
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
;
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
;
378 case sdbc::DataType::CHAR
:
379 case sdbc::DataType::VARCHAR
:
380 case sdbc::DataType::LONGVARCHAR
:
381 bEmptyFlag
= (rStr
.Len() == 0 && xRow
->wasNull());
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
;
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
;
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
;
423 case sdbc::DataType::SQLNULL
:
424 case sdbc::DataType::BINARY
:
425 case sdbc::DataType::VARBINARY
:
426 case sdbc::DataType::LONGVARBINARY
:
431 catch (uno::Exception
&)
436 void ScDPCacheTable::fillTable(const Reference
<sdbc::XRowSet
>& xRowSet
, const Date
& rNullDate
)
439 // Dont' even waste time to go any further.
444 Reference
<sdbc::XResultSetMetaDataSupplier
> xMetaSupp(xRowSet
, UNO_QUERY_THROW
);
445 Reference
<sdbc::XResultSetMetaData
> xMeta
= xMetaSupp
->getMetaData();
449 sal_Int32 nColCount
= xMeta
->getColumnCount();
451 // Get column titles and types.
452 vector
<sal_Int32
> aColTypes(nColCount
);
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
);
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
;
487 lcl_GetCellValue(xRow
, aColTypes
[nCol
], nCol
+1, rNullDate
, aCellContent
, aStr
, mrSharedString
);
488 rCell
.mpContent
= mpCollection
->getCacheCellFromPool(aCellContent
);
491 if (rCell
.mpContent
->mbNumeric
)
492 pNew
= new TypedStrData(aStr
, rCell
.mpContent
->mfValue
, SC_STRTYPE_VALUE
);
494 pNew
= new TypedStrData(aStr
);
496 if (!maFieldEntries
[nCol
]->Insert(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
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!
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()) )
536 const vector
<Cell
>& rRow
= maTable
[nRow
];
537 if ( nCol
< 0 || static_cast<size_t>(nCol
) >= rRow
.size() )
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()))
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();
575 // no data to filter.
578 // Row first, then column.
579 vector
< Sequence
<Any
> > tableData
;
580 tableData
.reserve(nRowSize
+1);
583 Sequence
<Any
> headerRow(nColSize
);
584 for (sal_Int32 nCol
= 0; nCol
< nColSize
; ++nCol
)
587 const String
* pStr
= mrSharedString
.getString(maHeader
[nCol
]);
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.
604 if (!isRowQualified(nRow
, rCriteria
, rRepeatIfEmptyDims
))
607 // Insert this row into table.
609 Sequence
<Any
> row(nColSize
);
610 for (SCCOL nCol
= 0; nCol
< nColSize
; ++nCol
)
613 bool bRepeatIfEmpty
= rRepeatIfEmptyDims
.count(nCol
) > 0;
614 const ScDPCacheCell
* pCell
= getCell(nCol
, nRow
, bRepeatIfEmpty
);
617 // This should never happen, but in case this happens, just
618 // stick in an empty string.
625 if (pCell
->mbNumeric
)
626 any
<<= pCell
->mfValue
;
630 const String
* pStr
= mrSharedString
.getString(pCell
->mnStrId
);
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()
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.
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
);
676 // This should never happen, but just in case...
679 if (!itr
->mpFilter
->match(*pCell
))
685 void ScDPCacheTable::getValueData(ScDocument
* pDoc
, const ScAddress
& rPos
, ScDPCacheCell
& rCell
)
687 ScBaseCell
* pCell
= pDoc
->GetCell(rPos
);
690 rCell
.mnType
= SC_VALTYPE_EMPTY
;
694 CellType eType
= pCell
->GetCellType();
695 if (eType
== CELLTYPE_NOTE
)
698 rCell
.mnType
= SC_VALTYPE_EMPTY
;
702 if (eType
== CELLTYPE_FORMULA
&& static_cast<ScFormulaCell
*>(pCell
)->GetErrCode())
704 // formula cell with error
705 rCell
.mnType
= SC_VALTYPE_ERROR
;
709 if ( pCell
->HasValueData() )
711 if (eType
== CELLTYPE_VALUE
)
713 rCell
.mfValue
= static_cast<ScValueCell
*>(pCell
)->GetValue();
714 else if (eType
== CELLTYPE_FORMULA
)
716 rCell
.mfValue
= static_cast<ScFormulaCell
*>(pCell
)->GetValue();
718 rCell
.mbNumeric
= true;
719 rCell
.mnType
= SC_VALTYPE_VALUE
;