xref: /AOO41X/main/sc/source/core/data/dptablecache.cxx (revision ffad8df045fe8db79e3e50f731c1fa6ab6501c83)
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, " dimention 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