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