Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "dpfilteredcache.hxx"
21 : #include "document.hxx"
22 : #include "address.hxx"
23 : #include "formulacell.hxx"
24 : #include "dptabdat.hxx"
25 : #include "dptabsrc.hxx"
26 : #include "dpobject.hxx"
27 : #include "queryparam.hxx"
28 : #include "queryentry.hxx"
29 : #include "dpitemdata.hxx"
30 :
31 : #include <com/sun/star/i18n/LocaleDataItem.hpp>
32 : #include <com/sun/star/sdbc/DataType.hpp>
33 : #include <com/sun/star/sdbc/XRow.hpp>
34 : #include <com/sun/star/sdbc/XRowSet.hpp>
35 : #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
36 : #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
37 : #include <com/sun/star/util/Date.hpp>
38 : #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
39 : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
40 :
41 : using namespace ::com::sun::star;
42 :
43 : using ::std::vector;
44 : using ::std::pair;
45 : using ::com::sun::star::i18n::LocaleDataItem;
46 : using ::com::sun::star::uno::Exception;
47 : using ::com::sun::star::uno::Reference;
48 : using ::com::sun::star::uno::Sequence;
49 : using ::com::sun::star::uno::Any;
50 : using ::com::sun::star::uno::UNO_QUERY;
51 : using ::com::sun::star::uno::UNO_QUERY_THROW;
52 : using ::com::sun::star::sheet::DataPilotFieldFilter;
53 :
54 460 : ScDPFilteredCache::SingleFilter::SingleFilter(const ScDPItemData& rItem) :
55 460 : maItem(rItem) {}
56 :
57 900 : bool ScDPFilteredCache::SingleFilter::match(const ScDPItemData& rCellData) const
58 : {
59 900 : return maItem == rCellData;
60 : }
61 :
62 0 : std::vector<ScDPItemData> ScDPFilteredCache::SingleFilter::getMatchValues() const
63 : {
64 0 : std::vector<ScDPItemData> aValues;
65 0 : aValues.push_back(maItem);
66 0 : return aValues;
67 : }
68 :
69 555 : ScDPFilteredCache::GroupFilter::GroupFilter()
70 : {
71 555 : }
72 :
73 27 : bool ScDPFilteredCache::GroupFilter::match(const ScDPItemData& rCellData) const
74 : {
75 27 : vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end();
76 56 : for (; it != itEnd; ++it)
77 : {
78 42 : bool bMatch = *it == rCellData;
79 42 : if (bMatch)
80 13 : return true;
81 : }
82 14 : return false;
83 : }
84 :
85 0 : std::vector<ScDPItemData> ScDPFilteredCache::GroupFilter::getMatchValues() const
86 : {
87 0 : return maItems;
88 : }
89 :
90 2755 : void ScDPFilteredCache::GroupFilter::addMatchItem(const ScDPItemData& rItem)
91 : {
92 2755 : maItems.push_back(rItem);
93 2755 : }
94 :
95 555 : size_t ScDPFilteredCache::GroupFilter::getMatchItemCount() const
96 : {
97 555 : return maItems.size();
98 : }
99 :
100 1015 : ScDPFilteredCache::Criterion::Criterion() :
101 : mnFieldIndex(-1),
102 1015 : mpFilter(static_cast<FilterBase*>(NULL))
103 : {
104 1015 : }
105 :
106 82 : ScDPFilteredCache::ScDPFilteredCache(const ScDPCache& rCache) :
107 82 : maShowByFilter(0, MAXROW+1, false), maShowByPage(0, MAXROW+1, true), mrCache(rCache)
108 : {
109 82 : }
110 :
111 82 : ScDPFilteredCache::~ScDPFilteredCache()
112 : {
113 82 : }
114 :
115 663 : sal_Int32 ScDPFilteredCache::getRowSize() const
116 : {
117 663 : return mrCache.GetRowCount();
118 : }
119 :
120 86615 : sal_Int32 ScDPFilteredCache::getColSize() const
121 : {
122 86615 : return mrCache.GetColumnCount();
123 : }
124 :
125 306 : void ScDPFilteredCache::fillTable(
126 : const ScQueryParam& rQuery, bool bIgnoreEmptyRows, bool bRepeatIfEmpty)
127 : {
128 306 : SCROW nRowCount = getRowSize();
129 306 : SCROW nDataSize = mrCache.GetDataSize();
130 306 : SCCOL nColCount = getColSize();
131 306 : if (nRowCount <= 0 || nColCount <= 0)
132 464 : return;
133 :
134 148 : maShowByFilter.clear();
135 148 : maShowByPage.clear();
136 148 : maShowByPage.build_tree();
137 :
138 : // Process the non-empty data rows.
139 1216 : for (SCROW nRow = 0; nRow < nDataSize; ++nRow)
140 : {
141 1068 : if (!getCache()->ValidQuery(nRow, rQuery))
142 30 : continue;
143 :
144 1038 : if (bIgnoreEmptyRows && getCache()->IsRowEmpty(nRow))
145 0 : continue;
146 :
147 1038 : maShowByFilter.insert_back(nRow, nRow+1, true);
148 : }
149 :
150 : // Process the trailing empty rows.
151 148 : if (!bIgnoreEmptyRows)
152 145 : maShowByFilter.insert_back(nDataSize, nRowCount, true);
153 :
154 148 : maShowByFilter.build_tree();
155 :
156 : // Initialize field entries container.
157 148 : maFieldEntries.clear();
158 148 : maFieldEntries.reserve(nColCount);
159 :
160 : // Build unique field entries.
161 797 : for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
162 : {
163 649 : maFieldEntries.push_back( vector<SCROW>() );
164 649 : SCROW nMemCount = getCache()->GetDimMemberCount( nCol );
165 649 : if (!nMemCount)
166 0 : continue;
167 :
168 649 : std::vector<SCROW> aAdded(nMemCount, -1);
169 649 : bool bShow = false;
170 649 : SCROW nEndSegment = -1;
171 6586 : for (SCROW nRow = 0; nRow < nRowCount; ++nRow)
172 : {
173 5937 : if (nRow > nEndSegment)
174 : {
175 773 : if (!maShowByFilter.search_tree(nRow, bShow, NULL, &nEndSegment).second)
176 : {
177 : OSL_FAIL("Tree search failed!");
178 0 : continue;
179 : }
180 773 : --nEndSegment; // End position is not inclusive. Move back one.
181 : }
182 :
183 5937 : if (!bShow)
184 : {
185 124 : nRow = nEndSegment;
186 124 : continue;
187 : }
188 :
189 5813 : SCROW nIndex = getCache()->GetItemDataId(nCol, nRow, bRepeatIfEmpty);
190 5813 : SCROW nOrder = getOrder(nCol, nIndex);
191 5813 : aAdded[nOrder] = nIndex;
192 : }
193 3983 : for (SCROW nRow = 0; nRow < nMemCount; ++nRow)
194 : {
195 3334 : if (aAdded[nRow] != -1)
196 3210 : maFieldEntries.back().push_back(aAdded[nRow]);
197 : }
198 649 : }
199 : }
200 :
201 1 : void ScDPFilteredCache::fillTable()
202 : {
203 1 : SCROW nRowCount = getRowSize();
204 1 : SCCOL nColCount = getColSize();
205 1 : if (nRowCount <= 0 || nColCount <= 0)
206 1 : return;
207 :
208 1 : maShowByPage.clear();
209 1 : maShowByPage.build_tree();
210 :
211 1 : maShowByFilter.clear();
212 1 : maShowByFilter.insert_front(0, nRowCount, true);
213 1 : maShowByFilter.build_tree();
214 :
215 : // Initialize field entries container.
216 1 : maFieldEntries.clear();
217 1 : maFieldEntries.reserve(nColCount);
218 :
219 : // Data rows
220 4 : for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
221 : {
222 3 : maFieldEntries.push_back( vector<SCROW>() );
223 3 : SCROW nMemCount = getCache()->GetDimMemberCount( nCol );
224 3 : if (!nMemCount)
225 0 : continue;
226 :
227 3 : std::vector<SCROW> aAdded(nMemCount, -1);
228 :
229 21 : for (SCROW nRow = 0; nRow < nRowCount; ++nRow)
230 : {
231 18 : SCROW nIndex = getCache()->GetItemDataId(nCol, nRow, false);
232 18 : SCROW nOrder = getOrder(nCol, nIndex);
233 18 : aAdded[nOrder] = nIndex;
234 : }
235 18 : for (SCROW nRow = 0; nRow < nMemCount; ++nRow)
236 : {
237 15 : if (aAdded[nRow] != -1)
238 15 : maFieldEntries.back().push_back(aAdded[nRow]);
239 : }
240 3 : }
241 : }
242 :
243 1137 : bool ScDPFilteredCache::isRowActive(sal_Int32 nRow, sal_Int32* pLastRow) const
244 : {
245 1137 : bool bFilter = false, bPage = true;
246 1137 : SCROW nLastRowFilter = MAXROW, nLastRowPage = MAXROW;
247 1137 : maShowByFilter.search_tree(nRow, bFilter, NULL, &nLastRowFilter);
248 1137 : maShowByPage.search_tree(nRow, bPage, NULL, &nLastRowPage);
249 1137 : if (pLastRow)
250 : {
251 : // Return the last row of current segment.
252 1131 : *pLastRow = nLastRowFilter < nLastRowPage ? nLastRowFilter : nLastRowPage;
253 1131 : *pLastRow -= 1; // End position is not inclusive. Move back one.
254 : }
255 :
256 1137 : return bFilter && bPage;
257 : }
258 :
259 4 : void ScDPFilteredCache::filterByPageDimension(const vector<Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rRepeatIfEmptyDims)
260 : {
261 4 : SCROW nRowSize = getRowSize();
262 :
263 4 : maShowByPage.clear();
264 :
265 31 : for (SCROW nRow = 0; nRow < nRowSize; ++nRow)
266 : {
267 27 : bool bShow = isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims);
268 27 : maShowByPage.insert_back(nRow, nRow+1, bShow);
269 : }
270 :
271 4 : maShowByPage.build_tree();
272 4 : }
273 :
274 1698 : const ScDPItemData* ScDPFilteredCache::getCell(SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
275 : {
276 1698 : SCROW nId= mrCache.GetItemDataId(nCol, nRow, bRepeatIfEmpty);
277 1698 : return mrCache.GetItemDataById( nCol, nId );
278 : }
279 :
280 446 : void ScDPFilteredCache::getValue( ScDPValue& rVal, SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
281 : {
282 446 : const ScDPItemData* pData = getCell( nCol, nRow, bRepeatIfEmpty );
283 :
284 446 : if (pData)
285 : {
286 446 : rVal.mfValue = pData->IsValue() ? pData->GetValue() : 0.0;
287 446 : rVal.meType = pData->GetCellType();
288 : }
289 : else
290 0 : rVal.Set(0.0, ScDPValue::Empty);
291 446 : }
292 :
293 26310 : OUString ScDPFilteredCache::getFieldName(SCCOL nIndex) const
294 : {
295 26310 : return mrCache.GetDimensionName(nIndex);
296 : }
297 :
298 1043 : const ::std::vector<SCROW>& ScDPFilteredCache::getFieldEntries( sal_Int32 nColumn ) const
299 : {
300 1043 : if (nColumn < 0 || static_cast<size_t>(nColumn) >= maFieldEntries.size())
301 : {
302 : // index out of bound. Hopefully this code will never be reached.
303 0 : static const ::std::vector<SCROW> emptyEntries;
304 0 : return emptyEntries;
305 : }
306 1043 : return maFieldEntries[nColumn];
307 : }
308 :
309 133 : void ScDPFilteredCache::filterTable(const vector<Criterion>& rCriteria, Sequence< Sequence<Any> >& rTabData,
310 : const boost::unordered_set<sal_Int32>& rRepeatIfEmptyDims)
311 : {
312 133 : sal_Int32 nRowSize = getRowSize();
313 133 : sal_Int32 nColSize = getColSize();
314 :
315 133 : if (!nRowSize)
316 : // no data to filter.
317 133 : return;
318 :
319 : // Row first, then column.
320 133 : vector< Sequence<Any> > tableData;
321 133 : tableData.reserve(nRowSize+1);
322 :
323 : // Header first.
324 266 : Sequence<Any> headerRow(nColSize);
325 798 : for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
326 : {
327 665 : OUString str;
328 665 : str = getFieldName( nCol);
329 1330 : Any any;
330 665 : any <<= str;
331 665 : headerRow[nCol] = any;
332 665 : }
333 133 : tableData.push_back(headerRow);
334 :
335 798 : for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
336 : {
337 : sal_Int32 nLastRow;
338 665 : if (!isRowActive(nRow, &nLastRow))
339 : {
340 : // This row is filtered out.
341 0 : nRow = nLastRow;
342 600 : continue;
343 : }
344 :
345 665 : if (!isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims))
346 600 : continue;
347 :
348 : // Insert this row into table.
349 :
350 65 : Sequence<Any> row(nColSize);
351 390 : for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
352 : {
353 325 : Any any;
354 325 : bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(nCol) > 0;
355 325 : const ScDPItemData* pData= getCell(nCol, nRow, bRepeatIfEmpty);
356 325 : if ( pData->IsValue() )
357 325 : any <<= pData->GetValue();
358 : else
359 : {
360 0 : OUString string (pData->GetString() );
361 0 : any <<= string;
362 : }
363 325 : row[nCol] = any;
364 325 : }
365 65 : tableData.push_back(row);
366 65 : }
367 :
368 : // convert vector to Seqeunce
369 133 : sal_Int32 nTabSize = static_cast<sal_Int32>(tableData.size());
370 133 : rTabData.realloc(nTabSize);
371 331 : for (sal_Int32 i = 0; i < nTabSize; ++i)
372 331 : rTabData[i] = tableData[i];
373 : }
374 :
375 8379 : SCROW ScDPFilteredCache::getOrder(long nDim, SCROW nIndex) const
376 : {
377 8379 : return mrCache.GetOrder(nDim, nIndex);
378 : }
379 :
380 163 : void ScDPFilteredCache::clear()
381 : {
382 163 : maFieldEntries.clear();
383 163 : maShowByFilter.clear();
384 163 : maShowByPage.clear();
385 163 : }
386 :
387 88002 : bool ScDPFilteredCache::empty() const
388 : {
389 88002 : return maFieldEntries.empty();
390 : }
391 :
392 692 : bool ScDPFilteredCache::isRowQualified(sal_Int32 nRow, const vector<Criterion>& rCriteria,
393 : const boost::unordered_set<sal_Int32>& rRepeatIfEmptyDims) const
394 : {
395 692 : sal_Int32 nColSize = getColSize();
396 692 : vector<Criterion>::const_iterator itrEnd = rCriteria.end();
397 1005 : for (vector<Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
398 : {
399 927 : if (itr->mnFieldIndex >= nColSize)
400 : // specified field is outside the source data columns. Don't
401 : // use this criterion.
402 0 : continue;
403 :
404 : // Check if the 'repeat if empty' flag is set for this field.
405 927 : bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(itr->mnFieldIndex) > 0;
406 927 : const ScDPItemData* pCellData = getCell(static_cast<SCCOL>(itr->mnFieldIndex), nRow, bRepeatIfEmpty);
407 927 : if (!itr->mpFilter->match(*pCellData))
408 614 : return false;
409 : }
410 78 : return true;
411 : }
412 :
413 27296 : const ScDPCache* ScDPFilteredCache::getCache() const
414 : {
415 27296 : return &mrCache;
416 102 : }
417 :
418 : #if DEBUG_PIVOT_TABLE
419 : using std::cout;
420 : using std::endl;
421 :
422 : void ScDPFilteredCache::dumpRowFlag(const RowFlagType& rFlag) const
423 : {
424 : RowFlagType::const_iterator it = rFlag.begin(), itEnd = rFlag.end();
425 : bool bShow = it->second;
426 : SCROW nRow1 = it->first;
427 : for (++it; it != itEnd; ++it)
428 : {
429 : SCROW nRow2 = it->first;
430 : cout << " * range " << nRow1 << "-" << nRow2 << ": " << (bShow ? "on" : "off") << endl;
431 : bShow = it->second;
432 : nRow1 = nRow2;
433 : }
434 : }
435 :
436 : void ScDPFilteredCache::dump() const
437 : {
438 : cout << "--- pivot filtered cache dump" << endl;
439 :
440 : cout << endl;
441 : cout << "* show by filter" << endl;
442 : dumpRowFlag(maShowByFilter);
443 :
444 : cout << endl;
445 : cout << "* show by page dimensions" << endl;
446 : dumpRowFlag(maShowByPage);
447 :
448 : cout << endl;
449 : cout << "* field entries" << endl;
450 : size_t nFieldCount = maFieldEntries.size();
451 : for (size_t i = 0; i < nFieldCount; ++i)
452 : {
453 : const vector<SCROW>& rField = maFieldEntries[i];
454 : cout << " * field " << i << endl;
455 : for (size_t j = 0, n = rField.size(); j < n; ++j)
456 : cout << " ID: " << rField[j] << endl;
457 : }
458 : cout << "---" << endl;
459 : }
460 :
461 : #endif
462 :
463 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|