1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_sc.hxx"
25 // INCLUDE ---------------------------------------------------------------
26 #include "dptablecache.hxx"
27 #include "dptabdat.hxx"
28 #include "document.hxx"
29 #include "cell.hxx"
30 #include "globstr.hrc"
31
32 #include <rtl/math.hxx>
33 #include "queryparam.hxx"
34 #include "dpglobal.hxx"
35
36 #include "docoptio.hxx" //for ValidQuery
37 #include <unotools/textsearch.hxx> //for ValidQuery
38
39 #include <com/sun/star/sdbc/DataType.hpp>
40 #include <com/sun/star/sdbc/XRow.hpp>
41 #include <com/sun/star/sdbc/XRowSet.hpp>
42 #include <com/sun/star/sdbc/XResultSetMetaData.hpp>
43 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
44 const double D_TIMEFACTOR = 86400.0;
45
46 using namespace ::com::sun::star;
47
48 using ::com::sun::star::uno::Exception;
49 using ::com::sun::star::uno::Reference;
50 using ::com::sun::star::uno::UNO_QUERY;
51 using ::com::sun::star::uno::UNO_QUERY_THROW;
52
53 // -----------------------------------------------------------------------
54 namespace
55 {
lcl_isDate(sal_uLong nNumType)56 sal_Bool lcl_isDate( sal_uLong nNumType )
57 {
58 return ( (nNumType & NUMBERFORMAT_DATE) != 0 )? 1:0 ;
59 }
60
lcl_Search(const std::vector<ScDPItemData * > & list,const::std::vector<SCROW> & rOrder,const ScDPItemData & item,SCROW & rIndex)61 sal_Bool lcl_Search( const std::vector<ScDPItemData*>& list, const ::std::vector<SCROW>& rOrder, const ScDPItemData& item, SCROW& rIndex)
62 {
63 rIndex = list.size();
64 sal_Bool bFound = sal_False;
65 SCROW nLo = 0;
66 SCROW nHi = list.size() - 1;
67 SCROW nIndex;
68 long nCompare;
69 while (nLo <= nHi)
70 {
71 nIndex = (nLo + nHi) / 2;
72 nCompare = ScDPItemData::Compare( *list[rOrder[nIndex]], item );
73 if (nCompare < 0)
74 nLo = nIndex + 1;
75 else
76 {
77 nHi = nIndex - 1;
78 if (nCompare == 0)
79 {
80 bFound = sal_True;
81 nLo = nIndex;
82 }
83 }
84 }
85 rIndex = nLo;
86 return bFound;
87 }
88
lcl_GetItemValue(const Reference<sdbc::XRow> & xRow,sal_Int32 nType,long nCol,const Date & rNullDate)89 ScDPItemData* lcl_GetItemValue(const Reference<sdbc::XRow>& xRow, sal_Int32 nType, long nCol,
90 const Date& rNullDate )
91 {
92 short nNumType = NUMBERFORMAT_NUMBER;
93 try
94 {
95 String rStr = xRow->getString(nCol);
96 double fValue = 0.0;
97 switch (nType)
98 {
99 case sdbc::DataType::BIT:
100 case sdbc::DataType::BOOLEAN:
101 {
102 nNumType = NUMBERFORMAT_LOGICAL;
103 fValue = xRow->getBoolean(nCol) ? 1 : 0;
104 return new ScDPItemData( rStr, fValue,sal_True,nNumType);
105 }
106 //break;
107
108 case sdbc::DataType::TINYINT:
109 case sdbc::DataType::SMALLINT:
110 case sdbc::DataType::INTEGER:
111 case sdbc::DataType::BIGINT:
112 case sdbc::DataType::FLOAT:
113 case sdbc::DataType::REAL:
114 case sdbc::DataType::DOUBLE:
115 case sdbc::DataType::NUMERIC:
116 case sdbc::DataType::DECIMAL:
117 {
118 //! do the conversion here?
119 fValue = xRow->getDouble(nCol);
120 return new ScDPItemData( rStr, fValue,sal_True);
121 }
122 //break;
123
124 case sdbc::DataType::DATE:
125 {
126 nNumType = NUMBERFORMAT_DATE;
127
128 util::Date aDate = xRow->getDate(nCol);
129 fValue = Date(aDate.Day, aDate.Month, aDate.Year) - rNullDate;
130 return new ScDPItemData( rStr, fValue, sal_True, nNumType );
131 }
132 //break;
133
134 case sdbc::DataType::TIME:
135 {
136 nNumType = NUMBERFORMAT_TIME;
137
138 util::Time aTime = xRow->getTime(nCol);
139 fValue = ( aTime.Hours * 3600 + aTime.Minutes * 60 +
140 aTime.Seconds + aTime.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
141 return new ScDPItemData( rStr,fValue, sal_True, nNumType );
142 }
143 //break;
144
145 case sdbc::DataType::TIMESTAMP:
146 {
147 nNumType = NUMBERFORMAT_DATETIME;
148
149 util::DateTime aStamp = xRow->getTimestamp(nCol);
150 fValue = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) - rNullDate ) +
151 ( aStamp.Hours * 3600 + aStamp.Minutes * 60 +
152 aStamp.Seconds + aStamp.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
153 return new ScDPItemData( rStr,fValue, sal_True, nNumType );
154 }
155 //break;
156 case sdbc::DataType::CHAR:
157 case sdbc::DataType::VARCHAR:
158 case sdbc::DataType::LONGVARCHAR:
159 case sdbc::DataType::SQLNULL:
160 case sdbc::DataType::BINARY:
161 case sdbc::DataType::VARBINARY:
162 case sdbc::DataType::LONGVARBINARY:
163 default:
164 return new ScDPItemData ( rStr );
165 //break;
166 }
167 }
168 catch (uno::Exception&)
169 {
170 }
171 catch ( ... )
172 {
173
174 }
175 return NULL;
176 }
177 }
178 // Wang Xu Ming -- 12/23/2008
179 //Refactor cache data
ScDPItemData(const String & rS,double fV,sal_Bool bHV,const sal_uLong nNumFormatP,sal_Bool bData)180 ScDPItemData::ScDPItemData( const String& rS, double fV/* = 0.0*/, sal_Bool bHV/* = sal_False*/, const sal_uLong nNumFormatP /*= 0*/ , sal_Bool bData/* = sal_True*/) :
181 nNumFormat( nNumFormatP ), aString(rS), fValue(fV),
182 mbFlag( (MK_VAL*!!bHV) | (MK_DATA*!!bData) | (MK_ERR*!!sal_False) | (MK_DATE*!!lcl_isDate( nNumFormat ) ) )
183 {
184 }
185
ScDPItemData(ScDocument * pDoc,SCROW nRow,sal_uInt16 nCol,sal_uInt16 nDocTab)186 ScDPItemData::ScDPItemData( ScDocument* pDoc, SCROW nRow, sal_uInt16 nCol, sal_uInt16 nDocTab ):
187 nNumFormat( 0 ), fValue(0.0), mbFlag( 0 )
188 {
189 String aDocStr;
190 pDoc->GetString( nCol, nRow, nDocTab, aDocStr );
191
192 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
193
194 ScAddress aPos( nCol, nRow, nDocTab );
195 ScBaseCell* pCell = pDoc->GetCell( aPos );
196
197 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell)->GetErrCode() )
198 {
199 SetString ( aDocStr );
200 //bErr = sal_True;
201 mbFlag |= MK_ERR;
202 }
203 else if ( pDoc->HasValueData( nCol, nRow, nDocTab ) )
204 {
205 double fVal = pDoc->GetValue(ScAddress(nCol, nRow, nDocTab));
206 nNumFormat = pDoc->GetNumberFormat( ScAddress( nCol, nRow, nDocTab ) );
207 sal_uLong nFormat = NUMBERFORMAT_NUMBER;
208 if ( pFormatter )
209 nFormat = pFormatter->GetType( nNumFormat );
210 aString = aDocStr;
211 fValue = fVal;
212 mbFlag |= MK_VAL|MK_DATA;
213 lcl_isDate( nFormat ) ? ( mbFlag |= MK_DATE ) : (mbFlag &= ~MK_DATE);
214 }
215 else if ( pDoc->HasData( nCol,nRow, nDocTab ) )
216 SetString ( aDocStr );
217 }
218 // End Comments
219
IsCaseInsEqual(const ScDPItemData & r) const220 sal_Bool ScDPItemData::IsCaseInsEqual( const ScDPItemData& r ) const
221 { //TODO: indified Date?
222 //! pass Transliteration?
223 //! inline?
224 return IsValue() ? ( r.IsValue() && rtl::math::approxEqual( fValue, r.fValue ) ) :
225 ( !r.IsValue() &&
226 ScGlobal::GetpTransliteration()->isEqual( aString, r.aString ) );
227 }
228
Hash() const229 size_t ScDPItemData::Hash() const
230 {
231 if ( IsValue() )
232 return (size_t) rtl::math::approxFloor( fValue );
233 else
234 // If we do unicode safe case insensitive hash we can drop
235 // ScDPItemData::operator== and use ::IsCasInsEqual
236 return rtl_ustr_hashCode_WithLength( aString.GetBuffer(), aString.Len() );
237 }
238
operator ==(const ScDPItemData & r) const239 sal_Bool ScDPItemData::operator==( const ScDPItemData& r ) const
240 {
241 if ( IsValue() )
242 {
243 if( (HasDatePart() != r.HasDatePart()) || (HasDatePart() && mnDatePart != r.mnDatePart) )
244 return sal_False;
245
246 // Wang Xu Ming -- 1/9/2009
247 // Add Data Cache Support.
248 // Identify date
249 if ( IsDate() != r.IsDate() )
250 return sal_False;
251 else
252 if ( r.IsValue() )
253 return rtl::math::approxEqual( fValue, r.fValue );
254 else
255 return sal_False;
256 // End Comments
257 }
258 else if ( r.IsValue() )
259 return sal_False;
260 else
261 // need exact equality until we have a safe case insensitive string hash
262 return aString == r.aString;
263 }
264
Compare(const ScDPItemData & rA,const ScDPItemData & rB)265 sal_Int32 ScDPItemData::Compare( const ScDPItemData& rA,
266 const ScDPItemData& rB )
267 {
268 if ( rA.IsValue() )
269 {
270 if ( rB.IsValue() )
271 {
272 if ( rtl::math::approxEqual( rA.fValue, rB.fValue ) )
273 {
274 // Wang Xu Ming -- 1/9/2009
275 // Add Data Cache Support.
276 // Date > number
277 if ( rA.IsDate() == rB.IsDate() )
278 return 0;
279 else
280 return rA.IsDate() ? 1: -1;
281 // End Comments
282 }
283 else if ( rA.fValue < rB.fValue )
284 return -1;
285 else
286 return 1;
287 }
288 else
289 return -1; // values first
290 }
291 else if ( rB.IsValue() )
292 return 1; // values first
293 else
294 return ScGlobal::GetCollator()->compareString( rA.aString, rB.aString );
295 }
296
297 #ifdef DEBUG
dump() const298 void ScDPItemData::dump() const
299 {
300 DBG_TRACE1( "Numberformat= %o", nNumFormat );
301 DBG_TRACESTR(aString );
302 DBG_TRACE1( "fValue= %f", fValue );
303 DBG_TRACE1( "mbFlag= %d", mbFlag);
304 }
305 #endif
306
CreateTypeString()307 TypedStrData* ScDPItemData::CreateTypeString( )
308 {
309 if ( IsValue() )
310 return new TypedStrData( aString, fValue, SC_STRTYPE_VALUE );
311 else
312 return new TypedStrData( aString );
313 }
314
GetType() const315 sal_uInt8 ScDPItemData::GetType() const
316 {
317
318 if ( IsHasErr() )
319 return SC_VALTYPE_ERROR;
320 else if ( !IsHasData() )
321 return SC_VALTYPE_EMPTY;
322 else if ( IsValue())
323 return SC_VALTYPE_VALUE;
324 else
325 return SC_VALTYPE_STRING;
326
327 }
328
IsHasData() const329 sal_Bool ScDPItemData::IsHasData() const
330 {
331 return !!(mbFlag&MK_DATA);
332 }
333
IsHasErr() const334 sal_Bool ScDPItemData::IsHasErr() const
335 {
336 return !!(mbFlag&MK_ERR);
337 }
338
IsValue() const339 sal_Bool ScDPItemData::IsValue() const
340 {
341 return !!(mbFlag&MK_VAL);
342 }
343
GetString() const344 String ScDPItemData::GetString() const
345 {
346
347 return aString;
348 }
349
GetValue() const350 double ScDPItemData::GetValue() const
351 {
352 return fValue;
353 }
GetNumFormat() const354 sal_uLong ScDPItemData::GetNumFormat() const
355 {
356 return nNumFormat;
357 }
358
HasStringData() const359 sal_Bool ScDPItemData::HasStringData() const
360
361 {
362 return IsHasData()&&!IsHasErr()&&!IsValue();
363 }
IsDate() const364 sal_Bool ScDPItemData::IsDate() const
365 {
366 return !!(mbFlag&MK_DATE);
367 }
HasDatePart() const368 sal_Bool ScDPItemData::HasDatePart() const
369 {
370 return !!(mbFlag&MK_DATEPART);
371 }
SetDate(sal_Bool b)372 void ScDPItemData::SetDate( sal_Bool b )
373 {
374 b ? ( mbFlag |= MK_DATE ) : ( mbFlag &= ~MK_DATE );
375 }
376
377 // -----------------------------------------------------------------------
378 //class ScDPTableDataCache
379 //To cache the pivot table data source
380
operator ==(const ScDPTableDataCache & r) const381 sal_Bool ScDPTableDataCache::operator== ( const ScDPTableDataCache& r ) const
382 {
383 if ( GetColumnCount() == r.GetColumnCount() )
384 {
385 for ( SCCOL i = 0 ; i < GetColumnCount(); i++ )
386 { //check dim names
387 if ( GetDimensionName( i ) != r.GetDimensionName( i ) )
388 return sal_False;
389 //check rows count
390 if ( GetRowCount() != r.GetRowCount() )
391 return sal_False;
392 //check dim member values
393 size_t nMembersCount = GetDimMemberValues( i ).size();
394 if ( GetDimMemberValues( i ).size() == r. GetDimMemberValues( i ).size() )
395 {
396 for ( size_t j = 0; j < nMembersCount; j++ )
397 {
398 if ( *( GetDimMemberValues( i )[j] ) == *( r.GetDimMemberValues( i )[j] ) )
399 continue;
400 else
401 return sal_False;
402 }
403 }
404 else
405 return sal_False;
406 //check source table index
407 for ( SCROW k=0 ; k < GetRowCount(); k ++ )
408 {
409 if ( GetItemDataId( i, k, sal_False ) == r.GetItemDataId( i,k,sal_False) )
410 continue;
411 else
412 return sal_False;
413 }
414 }
415 }
416 return sal_True;
417 }
418
ScDPTableDataCache(ScDocument * pDoc)419 ScDPTableDataCache::ScDPTableDataCache( ScDocument* pDoc ) :
420 mpDoc( pDoc ),
421 mnColumnCount ( 0 ),
422 mpTableDataValues ( NULL ),
423 mpSourceData ( NULL ),
424 mpGlobalOrder( NULL ),
425 mpIndexOrder( NULL)
426 {
427 mnID = -1;
428 }
429
~ScDPTableDataCache()430 ScDPTableDataCache::~ScDPTableDataCache()
431 {
432 if ( IsValid() )
433 {
434 // Wang Xu Ming -- 2/17/2009
435 // Performance issue
436 sal_uInt16 nCol;
437 for ( nCol=0; nCol < GetColumnCount() ; nCol++ )
438 {
439 for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ )
440 delete mpTableDataValues[nCol][row];
441 }
442 for ( nCol =0; nCol < mrLabelNames.size(); nCol++ )
443 delete mrLabelNames[nCol];
444 // End Comments
445
446 mnColumnCount = 0;
447 delete [] mpTableDataValues;
448 mpTableDataValues = NULL;
449 delete [] mpSourceData;
450 mpSourceData = NULL;
451 delete [] mpGlobalOrder;
452 mpGlobalOrder = NULL;
453 delete [] mpIndexOrder;
454 mpIndexOrder = NULL;
455 }
456 }
457
458 // -----------------------------------------------------------------------
AddRow(ScDPItemData * pRow,sal_uInt16 nCount)459 void ScDPTableDataCache::AddRow( ScDPItemData* pRow, sal_uInt16 nCount )
460 {
461 DBG_ASSERT( pRow , " empty pointer" );
462 if ( !mrLabelNames.size() )
463 {
464 mnColumnCount= nCount;
465 mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
466 mpSourceData = new std::vector<SCROW>[ mnColumnCount ];
467 mpGlobalOrder = new std::vector<SCROW>[ mnColumnCount ];
468 mpIndexOrder = new std::vector<SCROW>[ mnColumnCount ];
469
470 for ( sal_uInt16 i = 0; i < nCount ; i ++ )
471 AddLabel( new ScDPItemData( pRow[i] ) );
472 }
473 else
474 {
475 for ( sal_uInt16 i = 0; i < nCount && i < mnColumnCount; i ++ )
476 AddData( i, new ScDPItemData( pRow[i] ) );
477 }
478 }
479
480 // -----------------------------------------------------------------------
IsValid() const481 bool ScDPTableDataCache::IsValid() const
482 { //TODO: continue check valid
483 return mpTableDataValues!=NULL && mpSourceData!= NULL && mnColumnCount>0;
484 }
485
486 // -----------------------------------------------------------------------
487
488 namespace {
489
490 /**
491 * While the macro interpret level is incremented, the formula cells are
492 * (semi-)guaranteed to be interpreted.
493 */
494 class MacroInterpretIncrementer
495 {
496 public:
MacroInterpretIncrementer(ScDocument * pDoc)497 MacroInterpretIncrementer(ScDocument* pDoc) :
498 mpDoc(pDoc)
499 {
500 mpDoc->IncMacroInterpretLevel();
501 }
~MacroInterpretIncrementer()502 ~MacroInterpretIncrementer()
503 {
504 mpDoc->DecMacroInterpretLevel();
505 }
506 private:
507 ScDocument* mpDoc;
508 };
509
510 }
511
512 // -----------------------------------------------------------------------
InitFromDoc(ScDocument * pDoc,const ScRange & rRange)513 bool ScDPTableDataCache::InitFromDoc( ScDocument* pDoc, const ScRange& rRange )
514 {
515 // Make sure the formula cells within the data range are interpreted
516 // during this call, for this method may be called from the interpretation
517 // of GETPIVOTDATA, which disables nested formula interpretation without
518 // increasing the macro level.
519 MacroInterpretIncrementer aMacroInc(pDoc);
520
521 //
522 SCROW nStartRow = rRange.aStart.Row(); // start of data
523 SCROW nEndRow = rRange.aEnd.Row();
524 sal_uInt16 nStartCol = rRange.aStart.Col();
525 sal_uInt16 nEndCol = rRange.aEnd.Col();
526 sal_uInt16 nDocTab = rRange.aStart.Tab();
527
528 //init
529 long nOldColumCount = mnColumnCount;
530 mnColumnCount = nEndCol - nStartCol + 1;
531 if ( IsValid() )
532 {
533 for ( sal_uInt16 nCol=0; nCol < nOldColumCount ; nCol++ )
534 {
535 for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ )
536 delete mpTableDataValues[nCol][row];
537 delete mrLabelNames[nCol];
538 }
539 delete [] mpTableDataValues;
540 delete [] mpSourceData;
541 delete [] mpGlobalOrder;
542 delete [] mpIndexOrder;
543 mrLabelNames.clear();
544 }
545
546 mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
547 mpSourceData = new std::vector<SCROW>[ mnColumnCount ];
548 mpGlobalOrder = new std::vector<SCROW>[ mnColumnCount ];
549 mpIndexOrder = new std::vector<SCROW>[ mnColumnCount ];
550 pDoc->FillDPCache( this, nDocTab, nStartCol, nEndCol, nStartRow, nEndRow );
551 return sal_True;
552 }
553
554 // -----------------------------------------------------------------------
InitFromDataBase(const Reference<sdbc::XRowSet> & xRowSet,const Date & rNullDate)555 bool ScDPTableDataCache::InitFromDataBase (const Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate)
556 {
557 if (!xRowSet.is())
558 // Dont' even waste time to go any further.
559 return false;
560 try
561 {
562 Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(xRowSet, UNO_QUERY_THROW);
563 Reference<sdbc::XResultSetMetaData> xMeta = xMetaSupp->getMetaData();
564 if (!xMeta.is())
565 return false;
566
567 long nOldColumCount = mnColumnCount;
568 mnColumnCount = xMeta->getColumnCount();
569 if ( IsValid() )
570 {
571 for ( sal_uInt16 nCol=0; nCol < nOldColumCount ; nCol++ )
572 {
573 for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ )
574 delete mpTableDataValues[nCol][row];
575 delete mrLabelNames[nCol];
576 }
577 delete [] mpTableDataValues;
578 delete [] mpSourceData;
579 delete [] mpGlobalOrder;
580 delete [] mpIndexOrder;
581 mrLabelNames.clear();
582 }
583 // Get column titles and types.
584 mrLabelNames.reserve(mnColumnCount);
585 mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
586 mpSourceData = new std::vector<SCROW>[ mnColumnCount ];
587 mpGlobalOrder = new std::vector<SCROW>[ mnColumnCount ];
588 mpIndexOrder = new std::vector<SCROW>[ mnColumnCount ];
589
590 std::vector<sal_Int32> aColTypes(mnColumnCount);
591
592 for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol)
593 {
594 String aColTitle = xMeta->getColumnLabel(nCol+1);
595 aColTypes[nCol] = xMeta->getColumnType(nCol+1);
596 AddLabel( new ScDPItemData( aColTitle) );
597 }
598
599 // Now get the data rows.
600 Reference<sdbc::XRow> xRow(xRowSet, UNO_QUERY_THROW);
601 xRowSet->first();
602 do
603 {
604 for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol)
605 {
606 ScDPItemData * pNew = lcl_GetItemValue( xRow, aColTypes[nCol], nCol+1, rNullDate );
607 if ( pNew )
608 AddData( nCol , pNew );
609 }
610 }
611 while (xRowSet->next());
612
613 xRowSet->beforeFirst();
614
615 return true;
616 }
617 catch (const Exception&)
618 {
619 return false;
620 }
621 }
622 // -----------------------------------------------------------------------
GetDimNumType(SCCOL nDim) const623 sal_uLong ScDPTableDataCache::GetDimNumType( SCCOL nDim) const
624 {
625 DBG_ASSERT( IsValid(), " IsValid() == false " );
626 DBG_ASSERT( nDim < mnColumnCount && nDim >=0, " dimension out of bound " );
627 if ( mpTableDataValues[nDim].size()==0 )
628 return NUMBERFORMAT_UNDEFINED;
629 else
630 return GetNumType(mpTableDataValues[nDim][0]->nNumFormat);
631 }
632
633 // -----------------------------------------------------------------------
ValidQuery(SCROW nRow,const ScQueryParam & rParam,sal_Bool * pSpecial)634 bool ScDPTableDataCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam, sal_Bool *pSpecial)
635 { //Copied and modified from ScTable::ValidQuery
636 if (!rParam.GetEntry(0).bDoQuery)
637 return sal_True;
638 sal_Bool bMatchWholeCell = mpDoc->GetDocOptions().IsMatchWholeCell();
639
640 //---------------------------------------------------------------
641
642 const SCSIZE nFixedBools = 32;
643 sal_Bool aBool[nFixedBools];
644 sal_Bool aTest[nFixedBools];
645 SCSIZE nEntryCount = rParam.GetEntryCount();
646 sal_Bool* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new sal_Bool[nEntryCount] );
647 sal_Bool* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new sal_Bool[nEntryCount] );
648
649 long nPos = -1;
650 SCSIZE i = 0;
651 CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::GetCaseCollator() :
652 ScGlobal::GetCollator() );
653 ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ?
654 ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration());
655
656 while ( (i < nEntryCount) && rParam.GetEntry(i).bDoQuery )
657 {
658 ScQueryEntry& rEntry = rParam.GetEntry(i);
659 // we can only handle one single direct query
660 // #i115431# nField in QueryParam is the sheet column, not the field within the source range
661 SCCOL nQueryCol = (SCCOL)rEntry.nField;
662 if ( nQueryCol < rParam.nCol1 )
663 nQueryCol = rParam.nCol1;
664 if ( nQueryCol > rParam.nCol2 )
665 nQueryCol = rParam.nCol2;
666 SCCOL nSourceField = nQueryCol - rParam.nCol1;
667 SCROW nId = GetItemDataId( nSourceField, nRow, sal_False );
668 const ScDPItemData* pCellData = GetItemDataById( nSourceField, nId );
669
670 sal_Bool bOk = sal_False;
671 sal_Bool bTestEqual = sal_False;
672
673 if ( pSpecial && pSpecial[i] )
674 {
675 if (rEntry.nVal == SC_EMPTYFIELDS)
676 bOk = ! pCellData->IsHasData();
677 else // if (rEntry.nVal == SC_NONEMPTYFIELDS)
678 bOk = pCellData->IsHasData();
679 }
680 else if ( !rEntry.bQueryByString && pCellData->IsValue() )
681 { // by Value
682 double nCellVal = pCellData->GetValue();
683
684 switch (rEntry.eOp)
685 {
686 case SC_EQUAL :
687 bOk = ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
688 break;
689 case SC_LESS :
690 bOk = (nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
691 break;
692 case SC_GREATER :
693 bOk = (nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
694 break;
695 case SC_LESS_EQUAL :
696 bOk = (nCellVal < rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
697 break;
698 case SC_GREATER_EQUAL :
699 bOk = (nCellVal > rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
700 break;
701 case SC_NOT_EQUAL :
702 bOk = !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
703 break;
704 default:
705 bOk= sal_False;
706 break;
707 }
708 }
709 else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
710 || (rEntry.bQueryByString
711 && pCellData->HasStringData() )
712 )
713 { // by String
714 String aCellStr = pCellData->GetString();
715
716 sal_Bool bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
717 || (rEntry.eOp == SC_NOT_EQUAL)));
718 sal_Bool bTestRegExp = sal_False;
719 if ( bRealRegExp || bTestRegExp )
720 {
721 xub_StrLen nStart = 0;
722 xub_StrLen nEnd = aCellStr.Len();
723 sal_Bool bMatch = (sal_Bool) rEntry.GetSearchTextPtr( rParam.bCaseSens )
724 ->SearchFrwrd( aCellStr, &nStart, &nEnd );
725 // from 614 on, nEnd is behind the found text
726 if ( bMatch && bMatchWholeCell
727 && (nStart != 0 || nEnd != aCellStr.Len()) )
728 bMatch = sal_False; // RegExp must match entire cell string
729 if ( bRealRegExp )
730 bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch);
731 else
732 bTestEqual = bMatch;
733 }
734 if ( !bRealRegExp )
735 {
736 if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL )
737 {
738 if ( bMatchWholeCell )
739 {
740 bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr );
741
742 String aStr = *rEntry.pStr;//"f*"
743 //use another way to find "*" in aStr
744 sal_Bool bHasStar = sal_False;
745 xub_StrLen nIndex;
746 if( ( nIndex = aStr.Search('*') ) != STRING_NOTFOUND )
747 bHasStar = sal_True;
748 if(bHasStar && (nIndex>0))
749 {
750 for(i=0;(i<nIndex) && (i< aCellStr.Len()) ; i++)
751 {
752 if(aCellStr.GetChar( (sal_uInt16)i ) == aStr.GetChar((sal_uInt16) i ))
753 {
754 bOk=1;
755 }
756 else
757 {
758 bOk=0;
759 break;
760 }
761 }
762 }
763 //end modified
764 //Added end,20060808
765 }
766 else
767 {
768 ::com::sun::star::uno::Sequence< sal_Int32 > xOff;
769 String aCell( pTransliteration->transliterate(
770 aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(),
771 &xOff ) );
772 String aQuer( pTransliteration->transliterate(
773 *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(),
774 &xOff ) );
775 bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND);
776 }
777 if ( rEntry.eOp == SC_NOT_EQUAL )
778 bOk = !bOk;
779 }
780 else
781 { // use collator here because data was probably sorted
782 sal_Int32 nCompare = pCollator->compareString(
783 aCellStr, *rEntry.pStr );
784 switch (rEntry.eOp)
785 {
786 case SC_LESS :
787 bOk = (nCompare < 0);
788 break;
789 case SC_GREATER :
790 bOk = (nCompare > 0);
791 break;
792 case SC_LESS_EQUAL :
793 bOk = (nCompare <= 0);
794 break;
795 case SC_GREATER_EQUAL :
796 bOk = (nCompare >= 0);
797 break;
798 case SC_NOT_EQUAL:
799 DBG_ASSERT( false , "SC_NOT_EQUAL");
800 break;
801 case SC_TOPVAL:
802 case SC_BOTVAL:
803 case SC_TOPPERC:
804 case SC_BOTPERC:
805 default:
806 break;
807 }
808 }
809 }
810 }
811
812 if (nPos == -1)
813 {
814 nPos++;
815 pPasst[nPos] = bOk;
816 pTest[nPos] = bTestEqual;
817 }
818 else
819 {
820 if (rEntry.eConnect == SC_AND)
821 {
822 pPasst[nPos] = pPasst[nPos] && bOk;
823 pTest[nPos] = pTest[nPos] && bTestEqual;
824 }
825 else
826 {
827 nPos++;
828 pPasst[nPos] = bOk;
829 pTest[nPos] = bTestEqual;
830 }
831 }
832 i++;
833 }
834
835 for ( long j=1; j <= nPos; j++ )
836 {
837 pPasst[0] = pPasst[0] || pPasst[j];
838 pTest[0] = pTest[0] || pTest[j];
839 }
840
841 sal_Bool bRet = pPasst[0];
842 if ( pPasst != &aBool[0] )
843 delete [] pPasst;
844 if ( pTest != &aTest[0] )
845 delete [] pTest;
846
847 return bRet;
848 }
849
850 // -----------------------------------------------------------------------
IsRowEmpty(SCROW nRow) const851 bool ScDPTableDataCache::IsRowEmpty( SCROW nRow ) const
852 {
853 return mbEmptyRow[ nRow ];
854
855 }
856
857 // -----------------------------------------------------------------------
IsEmptyMember(SCROW nRow,sal_uInt16 nColumn) const858 bool ScDPTableDataCache::IsEmptyMember( SCROW nRow, sal_uInt16 nColumn ) const
859 {
860 return !GetItemDataById( nColumn, GetItemDataId( nColumn, nRow, sal_False ) )->IsHasData();
861 }
862
AddData(long nDim,ScDPItemData * pitemData,bool bCheckDate)863 sal_Bool ScDPTableDataCache::AddData(long nDim, ScDPItemData* pitemData, bool bCheckDate )
864 {
865 DBG_ASSERT( IsValid(), " IsValid() == false " );
866 DBG_ASSERT( nDim < mnColumnCount && nDim >=0 , "dimension out of bound" );
867 SCROW nIndex = 0;
868
869 sal_Bool bInserted = sal_False;
870 if( true == bCheckDate)
871 pitemData->SetDate( lcl_isDate( GetNumType( pitemData->nNumFormat ) ) );
872 if ( !lcl_Search( mpTableDataValues[nDim], mpGlobalOrder[nDim], *pitemData, nIndex ) )
873 {
874 mpTableDataValues[nDim].push_back( pitemData );
875 mpGlobalOrder[nDim].insert( mpGlobalOrder[nDim].begin()+nIndex, mpTableDataValues[nDim].size()-1 );
876 DBG_ASSERT( (size_t) mpGlobalOrder[nDim][nIndex] == mpTableDataValues[nDim].size()-1 ,"ScDPTableDataCache::AddData ");
877 mpSourceData[nDim].push_back( mpTableDataValues[nDim].size()-1 );
878 bInserted = sal_True;
879 }
880 else
881 mpSourceData[nDim].push_back( mpGlobalOrder[nDim][nIndex] );
882 //init empty row tag
883 size_t nCurRow = mpSourceData[nDim].size() -1 ;
884
885 while ( mbEmptyRow.size() <= nCurRow )
886 mbEmptyRow.push_back( sal_True );
887
888 if ( pitemData->IsHasData() )
889 mbEmptyRow[ nCurRow ] = sal_False;
890
891 if ( !bInserted )
892 delete pitemData;
893
894 return sal_True;
895 }
896
GetDimensionName(sal_uInt16 nColumn) const897 String ScDPTableDataCache::GetDimensionName( sal_uInt16 nColumn ) const
898 {
899 DBG_ASSERT( /* nColumn>=0 && */ nColumn < mrLabelNames.size()-1 , "ScDPTableDataCache::GetDimensionName");
900 DBG_ASSERT( mrLabelNames.size() == static_cast <sal_uInt16> (mnColumnCount+1), "ScDPTableDataCache::GetDimensionName");
901 if ( static_cast<size_t>(nColumn+1) < mrLabelNames.size() )
902 {
903 return mrLabelNames[nColumn+1]->aString;
904 }
905 else
906 return String();
907 }
908
909
AddLabel(ScDPItemData * pData)910 void ScDPTableDataCache::AddLabel(ScDPItemData *pData)
911 {
912 DBG_ASSERT( IsValid(), " IsValid() == false " );
913
914 if ( mrLabelNames.size() == 0 )
915 mrLabelNames.push_back( new ScDPItemData( ScGlobal::GetRscString(STR_PIVOT_DATA) ) );
916
917
918 //reset name if needed
919 String strNewName = pData->aString;
920
921 // #i116457# don't modify empty column titles
922 if ( strNewName.Len() )
923 {
924 sal_Bool bFound = sal_False;
925 long nIndex = 1;
926 do
927 {
928 for ( long i= mrLabelNames.size()-1; i>=0; i-- )
929 {
930 if( mrLabelNames[i]->aString == strNewName )
931 {
932 strNewName = pData->aString;
933 strNewName += String::CreateFromInt32( nIndex );
934 nIndex ++ ;
935 bFound = sal_True;
936 }
937 }
938 bFound = !bFound;
939 }
940 while ( !bFound );
941 }
942
943 pData->aString = strNewName;
944 mrLabelNames.push_back( pData );
945 }
946
GetItemDataId(sal_uInt16 nDim,SCROW nRow,sal_Bool bRepeatIfEmpty) const947 SCROW ScDPTableDataCache::GetItemDataId(sal_uInt16 nDim, SCROW nRow, sal_Bool bRepeatIfEmpty) const
948 { //
949 DBG_ASSERT( IsValid(), " IsValid() == false " );
950 DBG_ASSERT( /* nDim >= 0 && */ nDim < mnColumnCount, "ScDPTableDataCache::GetItemDataId " );
951
952 if ( bRepeatIfEmpty )
953 {
954 while ( nRow >0 && !mpTableDataValues[nDim][ mpSourceData[nDim][nRow] ]->IsHasData() )
955 --nRow;
956 }
957
958 return mpSourceData[nDim][nRow];
959 }
960
GetItemDataById(long nDim,SCROW nId) const961 const ScDPItemData* ScDPTableDataCache::GetItemDataById(long nDim, SCROW nId) const
962 {
963 if ( nId >= GetRowCount() )
964 return maAdditionalDatas.getData( nId - GetRowCount() );
965
966 if ( (size_t)nId >= mpTableDataValues[nDim].size() || nDim >= mnColumnCount || nId < 0 )
967 return NULL;
968 else
969 return mpTableDataValues[nDim][nId];
970 }
971
GetRowCount() const972 SCROW ScDPTableDataCache::GetRowCount() const
973 {
974 if ( IsValid() )
975 return mpSourceData[0].size();
976 else
977 return 0;
978 }
979
GetDimMemberValues(SCCOL nDim) const980 const std::vector<ScDPItemData*>& ScDPTableDataCache::GetDimMemberValues(SCCOL nDim) const
981 {
982 DBG_ASSERT( nDim>=0 && nDim < mnColumnCount ," nDim < mnColumnCount ");
983 return mpTableDataValues[nDim];
984 }
985
GetSortedItemDataId(SCCOL nDim,SCROW nOrder) const986 SCROW ScDPTableDataCache::GetSortedItemDataId(SCCOL nDim, SCROW nOrder) const
987 {
988 DBG_ASSERT ( IsValid(), "IsValid");
989 DBG_ASSERT( nDim>=0 && nDim < mnColumnCount, "nDim < mnColumnCount");
990 DBG_ASSERT( nOrder >= 0 && (size_t) nOrder < mpGlobalOrder[nDim].size(), "nOrder < mpGlobalOrder[nDim].size()" );
991
992 return mpGlobalOrder[nDim][nOrder];
993 }
994
GetNumType(sal_uLong nFormat) const995 sal_uLong ScDPTableDataCache::GetNumType(sal_uLong nFormat) const
996 {
997 SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
998 sal_uLong nType = NUMBERFORMAT_NUMBER;
999 if ( pFormatter )
1000 nType = pFormatter->GetType( nFormat );
1001 return nType;
1002 }
1003
GetNumberFormat(long nDim) const1004 sal_uLong ScDPTableDataCache::GetNumberFormat( long nDim ) const
1005 {
1006 if ( nDim >= mnColumnCount )
1007 return 0;
1008
1009 // #i113411# take the number format from the first value entry
1010 size_t nSize = mpTableDataValues[nDim].size();
1011 size_t nPos = 0;
1012 while ( nPos < nSize && mpTableDataValues[nDim][nPos]->GetType() != SC_VALTYPE_VALUE )
1013 ++nPos;
1014 if ( nPos < nSize )
1015 return mpTableDataValues[nDim][nPos]->nNumFormat;
1016 return 0;
1017 }
1018
IsDateDimension(long nDim) const1019 sal_Bool ScDPTableDataCache::IsDateDimension( long nDim ) const
1020 {
1021 if ( nDim >= mnColumnCount )
1022 return false;
1023 else if ( mpTableDataValues[nDim].size()==0 )
1024 return false;
1025 else
1026 return mpTableDataValues[nDim][0]->IsDate();
1027
1028 }
1029
GetDimMemberCount(SCCOL nDim) const1030 SCROW ScDPTableDataCache::GetDimMemberCount( SCCOL nDim ) const
1031 {
1032 DBG_ASSERT( nDim>=0 && nDim < mnColumnCount ," ScDPTableDataCache::GetDimMemberCount : out of bound ");
1033 return mpTableDataValues[nDim].size();
1034 }
1035
GetSortedItemData(SCCOL nDim,SCROW nOrder) const1036 const ScDPItemData* ScDPTableDataCache::GetSortedItemData(SCCOL nDim, SCROW nOrder) const
1037 {
1038 SCROW n = GetSortedItemDataId( nDim, nOrder );
1039 return GetItemDataById( nDim, n );
1040 }
1041
GetDimensionIndex(String sName) const1042 SCCOL ScDPTableDataCache::GetDimensionIndex(String sName) const
1043 {
1044 for ( size_t n = 1; n < mrLabelNames.size(); n ++ ) //defects, label name map wrong
1045 {
1046 if ( mrLabelNames[n]->GetString() == sName )
1047 return (SCCOL)(n-1);
1048 }
1049 return -1;
1050 }
1051
GetIdByItemData(long nDim,String sItemData) const1052 SCROW ScDPTableDataCache::GetIdByItemData(long nDim, String sItemData ) const
1053 {
1054 if ( nDim < mnColumnCount && nDim >=0 )
1055 {
1056 for ( size_t n = 0; n< mpTableDataValues[nDim].size(); n++ )
1057 {
1058 if ( mpTableDataValues[nDim][n]->GetString() == sItemData )
1059 return n;
1060 }
1061 }
1062
1063 ScDPItemData rData ( sItemData );
1064 return GetRowCount() +maAdditionalDatas.getDataId(rData);
1065 }
1066
GetIdByItemData(long nDim,const ScDPItemData & rData) const1067 SCROW ScDPTableDataCache::GetIdByItemData( long nDim, const ScDPItemData& rData ) const
1068 {
1069 if ( nDim < mnColumnCount && nDim >=0 )
1070 {
1071 for ( size_t n = 0; n< mpTableDataValues[nDim].size(); n++ )
1072 {
1073 if ( *mpTableDataValues[nDim][n] == rData )
1074 return n;
1075 }
1076 }
1077 return GetRowCount() + maAdditionalDatas.getDataId(rData);
1078 }
1079
GetAdditionalItemID(String sItemData)1080 SCROW ScDPTableDataCache::GetAdditionalItemID ( String sItemData )
1081 {
1082 ScDPItemData rData ( sItemData );
1083 return GetAdditionalItemID( rData );
1084 }
1085
GetAdditionalItemID(const ScDPItemData & rData)1086 SCROW ScDPTableDataCache::GetAdditionalItemID( const ScDPItemData& rData )
1087 {
1088 return GetRowCount() + maAdditionalDatas.insertData( rData );
1089 }
1090
1091
GetOrder(long nDim,SCROW nIndex) const1092 SCROW ScDPTableDataCache::GetOrder(long nDim, SCROW nIndex) const
1093 {
1094 DBG_ASSERT( IsValid(), " IsValid() == false " );
1095 DBG_ASSERT( nDim >=0 && nDim < mnColumnCount, "ScDPTableDataCache::GetOrder : out of bound" );
1096
1097 if ( mpIndexOrder[nDim].size() != mpGlobalOrder[nDim].size() )
1098 { //not inited
1099 SCROW i = 0;
1100 mpIndexOrder[nDim].resize( mpGlobalOrder[nDim].size(), 0 );
1101 for ( size_t n = 0 ; n< mpGlobalOrder[nDim].size(); n++ )
1102 {
1103 i = mpGlobalOrder[nDim][n];
1104 mpIndexOrder[nDim][ i ] = n;
1105 }
1106 }
1107
1108 DBG_ASSERT( nIndex>=0 && (size_t)nIndex < mpIndexOrder[nDim].size() , "ScDPTableDataCache::GetOrder");
1109 return mpIndexOrder[nDim][nIndex];
1110 }
1111
GetDoc() const1112 ScDocument* ScDPTableDataCache::GetDoc() const
1113 {
1114 return mpDoc;
1115 };
1116
GetColumnCount() const1117 long ScDPTableDataCache::GetColumnCount() const
1118 {
1119 return mnColumnCount;
1120 }
GetId() const1121 long ScDPTableDataCache::GetId() const
1122 {
1123 return mnID;
1124 }
1125