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 "cell.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 : #include <memory>
42 :
43 : using namespace ::com::sun::star;
44 :
45 : using ::rtl::OUString;
46 : using ::std::vector;
47 : using ::std::pair;
48 : using ::std::auto_ptr;
49 : using ::com::sun::star::i18n::LocaleDataItem;
50 : using ::com::sun::star::uno::Exception;
51 : using ::com::sun::star::uno::Reference;
52 : using ::com::sun::star::uno::Sequence;
53 : using ::com::sun::star::uno::Any;
54 : using ::com::sun::star::uno::UNO_QUERY;
55 : using ::com::sun::star::uno::UNO_QUERY_THROW;
56 : using ::com::sun::star::sheet::DataPilotFieldFilter;
57 :
58 200 : ScDPFilteredCache::SingleFilter::SingleFilter(const ScDPItemData& rItem) :
59 200 : maItem(rItem) {}
60 :
61 360 : bool ScDPFilteredCache::SingleFilter::match(const ScDPItemData& rCellData) const
62 : {
63 360 : return maItem == rCellData;
64 : }
65 :
66 0 : const ScDPItemData& ScDPFilteredCache::SingleFilter::getMatchValue() const
67 : {
68 0 : return maItem;
69 : }
70 :
71 228 : ScDPFilteredCache::GroupFilter::GroupFilter()
72 : {
73 228 : }
74 :
75 32 : bool ScDPFilteredCache::GroupFilter::match(const ScDPItemData& rCellData) const
76 : {
77 32 : vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end();
78 48 : for (; it != itEnd; ++it)
79 : {
80 32 : bool bMatch = *it == rCellData;
81 32 : if (bMatch)
82 16 : return true;
83 : }
84 16 : return false;
85 : }
86 :
87 1110 : void ScDPFilteredCache::GroupFilter::addMatchItem(const ScDPItemData& rItem)
88 : {
89 1110 : maItems.push_back(rItem);
90 1110 : }
91 :
92 228 : size_t ScDPFilteredCache::GroupFilter::getMatchItemCount() const
93 : {
94 228 : return maItems.size();
95 : }
96 :
97 : // ----------------------------------------------------------------------------
98 :
99 428 : ScDPFilteredCache::Criterion::Criterion() :
100 : mnFieldIndex(-1),
101 428 : mpFilter(static_cast<FilterBase*>(NULL))
102 : {
103 428 : }
104 :
105 : // ----------------------------------------------------------------------------
106 :
107 48 : ScDPFilteredCache::ScDPFilteredCache(const ScDPCache& rCache) :
108 48 : maShowByFilter(0, MAXROW+1, false), maShowByPage(0, MAXROW+1, true), mrCache(rCache)
109 : {
110 48 : }
111 :
112 48 : ScDPFilteredCache::~ScDPFilteredCache()
113 : {
114 48 : }
115 :
116 304 : sal_Int32 ScDPFilteredCache::getRowSize() const
117 : {
118 304 : return mrCache.GetRowCount();
119 : }
120 :
121 70868 : sal_Int32 ScDPFilteredCache::getColSize() const
122 : {
123 70868 : return mrCache.GetColumnCount();
124 : }
125 :
126 104 : void ScDPFilteredCache::fillTable(
127 : const ScQueryParam& rQuery, bool bIgnoreEmptyRows, bool bRepeatIfEmpty)
128 : {
129 104 : SCROW nRowCount = getRowSize();
130 104 : SCROW nDataSize = mrCache.GetDataSize();
131 104 : SCCOL nColCount = getColSize();
132 104 : if (nRowCount <= 0 || nColCount <= 0)
133 104 : return;
134 :
135 104 : maShowByFilter.clear();
136 104 : maShowByPage.clear();
137 104 : maShowByPage.build_tree();
138 :
139 : // Process the non-empty data rows.
140 768 : for (SCROW nRow = 0; nRow < nDataSize; ++nRow)
141 : {
142 664 : if (!getCache()->ValidQuery(nRow, rQuery))
143 36 : continue;
144 :
145 628 : if (bIgnoreEmptyRows && getCache()->IsRowEmpty(nRow))
146 0 : continue;
147 :
148 628 : maShowByFilter.insert_back(nRow, nRow+1, true);
149 : }
150 :
151 : // Process the trailing empty rows.
152 104 : if (!bIgnoreEmptyRows)
153 100 : maShowByFilter.insert_back(nDataSize, nRowCount, true);
154 :
155 104 : maShowByFilter.build_tree();
156 :
157 : // Initialize field entries container.
158 104 : maFieldEntries.clear();
159 104 : maFieldEntries.reserve(nColCount);
160 :
161 : // Build unique field entries.
162 502 : for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
163 : {
164 398 : maFieldEntries.push_back( vector<SCROW>() );
165 398 : SCROW nMemCount = getCache()->GetDimMemberCount( nCol );
166 398 : if (!nMemCount)
167 0 : continue;
168 :
169 398 : std::vector<SCROW> aAdded(nMemCount, -1);
170 398 : bool bShow = false;
171 398 : SCROW nEndSegment = -1;
172 2786 : for (SCROW nRow = 0; nRow < nRowCount; ++nRow)
173 : {
174 2388 : if (nRow > nEndSegment)
175 : {
176 526 : if (!maShowByFilter.search_tree(nRow, bShow, NULL, &nEndSegment))
177 : {
178 : OSL_FAIL("Tree search failed!");
179 0 : continue;
180 : }
181 526 : --nEndSegment; // End position is not inclusive. Move back one.
182 : }
183 :
184 2388 : if (!bShow)
185 : {
186 128 : nRow = nEndSegment;
187 128 : continue;
188 : }
189 :
190 2260 : SCROW nIndex = getCache()->GetItemDataId(nCol, nRow, bRepeatIfEmpty);
191 2260 : SCROW nOrder = getOrder(nCol, nIndex);
192 2260 : aAdded[nOrder] = nIndex;
193 : }
194 2460 : for (SCROW nRow = 0; nRow < nMemCount; ++nRow)
195 : {
196 2062 : if (aAdded[nRow] != -1)
197 1934 : maFieldEntries.back().push_back(aAdded[nRow]);
198 : }
199 398 : }
200 : }
201 :
202 2 : void ScDPFilteredCache::fillTable()
203 : {
204 2 : SCROW nRowCount = getRowSize();
205 2 : SCCOL nColCount = getColSize();
206 2 : if (nRowCount <= 0 || nColCount <= 0)
207 2 : return;
208 :
209 2 : maShowByPage.clear();
210 2 : maShowByPage.build_tree();
211 :
212 2 : maShowByFilter.clear();
213 2 : maShowByFilter.insert_front(0, nRowCount, true);
214 2 : maShowByFilter.build_tree();
215 :
216 : // Initialize field entries container.
217 2 : maFieldEntries.clear();
218 2 : maFieldEntries.reserve(nColCount);
219 :
220 : // Data rows
221 8 : for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
222 : {
223 6 : maFieldEntries.push_back( vector<SCROW>() );
224 6 : SCROW nMemCount = getCache()->GetDimMemberCount( nCol );
225 6 : if (!nMemCount)
226 0 : continue;
227 :
228 6 : std::vector<SCROW> aAdded(nMemCount, -1);
229 :
230 42 : for (SCROW nRow = 0; nRow < nRowCount; ++nRow)
231 : {
232 36 : SCROW nIndex = getCache()->GetItemDataId(nCol, nRow, false);
233 36 : SCROW nOrder = getOrder(nCol, nIndex);
234 36 : aAdded[nOrder] = nIndex;
235 : }
236 36 : for (SCROW nRow = 0; nRow < nMemCount; ++nRow)
237 : {
238 30 : if (aAdded[nRow] != -1)
239 30 : maFieldEntries.back().push_back(aAdded[nRow]);
240 : }
241 6 : }
242 : }
243 :
244 834 : bool ScDPFilteredCache::isRowActive(sal_Int32 nRow, sal_Int32* pLastRow) const
245 : {
246 834 : bool bFilter = false, bPage = true;
247 834 : SCROW nLastRowFilter = MAXROW, nLastRowPage = MAXROW;
248 834 : maShowByFilter.search_tree(nRow, bFilter, NULL, &nLastRowFilter);
249 834 : maShowByPage.search_tree(nRow, bPage, NULL, &nLastRowPage);
250 834 : if (pLastRow)
251 : {
252 : // Return the last row of current segment.
253 822 : *pLastRow = nLastRowFilter < nLastRowPage ? nLastRowFilter : nLastRowPage;
254 822 : *pLastRow -= 1; // End position is not inclusive. Move back one.
255 : }
256 :
257 834 : return bFilter && bPage;
258 : }
259 :
260 4 : void ScDPFilteredCache::filterByPageDimension(const vector<Criterion>& rCriteria, const boost::unordered_set<sal_Int32>& rRepeatIfEmptyDims)
261 : {
262 4 : SCROW nRowSize = getRowSize();
263 :
264 4 : maShowByPage.clear();
265 :
266 36 : for (SCROW nRow = 0; nRow < nRowSize; ++nRow)
267 : {
268 32 : bool bShow = isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims);
269 32 : maShowByPage.insert_back(nRow, nRow+1, bShow);
270 : }
271 :
272 4 : maShowByPage.build_tree();
273 4 : }
274 :
275 1034 : const ScDPItemData* ScDPFilteredCache::getCell(SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
276 : {
277 1034 : SCROW nId= mrCache.GetItemDataId(nCol, nRow, bRepeatIfEmpty);
278 1034 : return mrCache.GetItemDataById( nCol, nId );
279 : }
280 :
281 592 : void ScDPFilteredCache::getValue( ScDPValueData& rVal, SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
282 : {
283 592 : const ScDPItemData* pData = getCell( nCol, nRow, bRepeatIfEmpty );
284 :
285 592 : if (pData)
286 : {
287 592 : rVal.fValue = pData->IsValue() ? pData->GetValue() : 0.0;
288 592 : rVal.nType = pData->GetCellType();
289 : }
290 : else
291 0 : rVal.Set(0.0, SC_VALTYPE_EMPTY);
292 592 : }
293 :
294 18098 : rtl::OUString ScDPFilteredCache::getFieldName(SCCOL nIndex) const
295 : {
296 18098 : return mrCache.GetDimensionName(nIndex);
297 : }
298 :
299 1078 : const ::std::vector<SCROW>& ScDPFilteredCache::getFieldEntries( sal_Int32 nColumn ) const
300 : {
301 1078 : if (nColumn < 0 || static_cast<size_t>(nColumn) >= maFieldEntries.size())
302 : {
303 : // index out of bound. Hopefully this code will never be reached.
304 0 : static const ::std::vector<SCROW> emptyEntries;
305 0 : return emptyEntries;
306 : }
307 1078 : return maFieldEntries[nColumn];
308 : }
309 :
310 50 : void ScDPFilteredCache::filterTable(const vector<Criterion>& rCriteria, Sequence< Sequence<Any> >& rTabData,
311 : const boost::unordered_set<sal_Int32>& rRepeatIfEmptyDims)
312 : {
313 50 : sal_Int32 nRowSize = getRowSize();
314 50 : sal_Int32 nColSize = getColSize();
315 :
316 50 : if (!nRowSize)
317 : // no data to filter.
318 50 : return;
319 :
320 : // Row first, then column.
321 50 : vector< Sequence<Any> > tableData;
322 50 : tableData.reserve(nRowSize+1);
323 :
324 : // Header first.
325 50 : Sequence<Any> headerRow(nColSize);
326 300 : for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
327 : {
328 250 : OUString str;
329 250 : str = getFieldName( nCol);
330 250 : Any any;
331 250 : any <<= str;
332 250 : headerRow[nCol] = any;
333 250 : }
334 50 : tableData.push_back(headerRow);
335 :
336 300 : for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
337 : {
338 : sal_Int32 nLastRow;
339 250 : if (!isRowActive(nRow, &nLastRow))
340 : {
341 : // This row is filtered out.
342 0 : nRow = nLastRow;
343 0 : continue;
344 : }
345 :
346 250 : if (!isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims))
347 240 : continue;
348 :
349 : // Insert this row into table.
350 :
351 10 : Sequence<Any> row(nColSize);
352 60 : for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
353 : {
354 50 : Any any;
355 50 : bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(nCol) > 0;
356 50 : const ScDPItemData* pData= getCell(nCol, nRow, bRepeatIfEmpty);
357 50 : if ( pData->IsValue() )
358 50 : any <<= pData->GetValue();
359 : else
360 : {
361 0 : OUString string (pData->GetString() );
362 0 : any <<= string;
363 : }
364 50 : row[nCol] = any;
365 50 : }
366 10 : tableData.push_back(row);
367 10 : }
368 :
369 : // convert vector to Seqeunce
370 50 : sal_Int32 nTabSize = static_cast<sal_Int32>(tableData.size());
371 50 : rTabData.realloc(nTabSize);
372 110 : for (sal_Int32 i = 0; i < nTabSize; ++i)
373 110 : rTabData[i] = tableData[i];
374 : }
375 :
376 3992 : SCROW ScDPFilteredCache::getOrder(long nDim, SCROW nIndex) const
377 : {
378 3992 : return mrCache.GetOrder(nDim, nIndex);
379 : }
380 :
381 100 : void ScDPFilteredCache::clear()
382 : {
383 100 : maFieldEntries.clear();
384 100 : maShowByFilter.clear();
385 100 : maShowByPage.clear();
386 100 : }
387 :
388 72224 : bool ScDPFilteredCache::empty() const
389 : {
390 72224 : return maFieldEntries.empty();
391 : }
392 :
393 282 : bool ScDPFilteredCache::isRowQualified(sal_Int32 nRow, const vector<Criterion>& rCriteria,
394 : const boost::unordered_set<sal_Int32>& rRepeatIfEmptyDims) const
395 : {
396 282 : sal_Int32 nColSize = getColSize();
397 282 : vector<Criterion>::const_iterator itrEnd = rCriteria.end();
398 418 : for (vector<Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
399 : {
400 392 : if (itr->mnFieldIndex >= nColSize)
401 : // specified field is outside the source data columns. Don't
402 : // use this criterion.
403 0 : continue;
404 :
405 : // Check if the 'repeat if empty' flag is set for this field.
406 392 : bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(itr->mnFieldIndex) > 0;
407 392 : const ScDPItemData* pCellData = getCell(static_cast<SCCOL>(itr->mnFieldIndex), nRow, bRepeatIfEmpty);
408 392 : if (!itr->mpFilter->match(*pCellData))
409 256 : return false;
410 : }
411 26 : return true;
412 : }
413 :
414 14182 : const ScDPCache* ScDPFilteredCache::getCache() const
415 : {
416 14182 : return &mrCache;
417 102 : }
418 :
419 : #if DEBUG_PIVOT_TABLE
420 : #include <iostream>
421 : using std::cout;
422 : using std::endl;
423 :
424 : void ScDPFilteredCache::dumpRowFlag(const RowFlagType& rFlag) const
425 : {
426 : RowFlagType::const_iterator it = rFlag.begin(), itEnd = rFlag.end();
427 : bool bShow = it->second;
428 : SCROW nRow1 = it->first;
429 : for (++it; it != itEnd; ++it)
430 : {
431 : SCROW nRow2 = it->first;
432 : cout << " * range " << nRow1 << "-" << nRow2 << ": " << (bShow ? "on" : "off") << endl;
433 : bShow = it->second;
434 : nRow1 = nRow2;
435 : }
436 : }
437 :
438 : void ScDPFilteredCache::dump() const
439 : {
440 : cout << "--- pivot cache filter dump" << endl;
441 :
442 : cout << endl;
443 : cout << "* show by filter" << endl;
444 : dumpRowFlag(maShowByFilter);
445 :
446 : cout << endl;
447 : cout << "* show by page dimensions" << endl;
448 : dumpRowFlag(maShowByPage);
449 :
450 : cout << "---" << endl;
451 : }
452 :
453 : #endif
454 :
455 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|