xref: /AOO41X/main/sc/source/core/data/dptablecache.cxx (revision 54628ca40d27d15cc98fe861da7fff7e60c2f7d6)
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 {
56     sal_Bool lcl_isDate( sal_uLong nNumType )
57     {
58         return ( (nNumType & NUMBERFORMAT_DATE) != 0 )? 1:0 ;
59     }
60 
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 
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
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 
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 );      //[SODC_19347] add liyi
200         //bErr = sal_True;              //[SODC_19347] del liyi
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 
220 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 
229 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 
239 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 
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 //Wang Xu Ming SODC_17561
298 #ifdef DEBUG
299 void    ScDPItemData::dump() const
300 {
301     DBG_TRACE1( "Numberformat= %o",  nNumFormat );
302     DBG_TRACESTR(aString );
303     DBG_TRACE1( "fValue= %f", fValue );
304     DBG_TRACE1( "mbFlag= %d", mbFlag);
305 }
306 #endif
307 //End
308 
309 TypedStrData*  ScDPItemData::CreateTypeString( )
310 {
311     if ( IsValue() )
312         return new TypedStrData( aString, fValue, SC_STRTYPE_VALUE );
313     else
314         return new TypedStrData( aString );
315 }
316 
317 sal_uInt8 ScDPItemData::GetType() const
318 {
319 
320     if ( IsHasErr() )
321         return SC_VALTYPE_ERROR;
322     else if ( !IsHasData() )
323         return SC_VALTYPE_EMPTY;
324     else if ( IsValue())
325         return SC_VALTYPE_VALUE;
326     else
327         return SC_VALTYPE_STRING;
328 
329 }
330 
331 sal_Bool ScDPItemData::IsHasData() const
332 {
333     return !!(mbFlag&MK_DATA);
334 }
335 
336 sal_Bool ScDPItemData::IsHasErr() const
337 {
338     return !!(mbFlag&MK_ERR);
339 }
340 
341 sal_Bool ScDPItemData::IsValue() const
342 {
343     return !!(mbFlag&MK_VAL);
344 }
345 
346 String ScDPItemData::GetString() const
347 {
348 
349     return aString;
350 }
351 
352 double ScDPItemData::GetValue() const
353 {
354     return fValue;
355 }
356 sal_uLong  ScDPItemData::GetNumFormat() const
357 {
358     return nNumFormat;
359 }
360 
361 sal_Bool ScDPItemData::HasStringData() const
362 
363 {
364     return IsHasData()&&!IsHasErr()&&!IsValue();
365 }
366 sal_Bool ScDPItemData::IsDate() const
367 {
368     return !!(mbFlag&MK_DATE);
369 }
370 sal_Bool ScDPItemData::HasDatePart() const
371 {
372     return !!(mbFlag&MK_DATEPART);
373 }
374 void ScDPItemData::SetDate( sal_Bool b )
375 {
376     b ? ( mbFlag |= MK_DATE ) : ( mbFlag &= ~MK_DATE );
377 }
378 
379 // -----------------------------------------------------------------------
380 //class ScDPTableDataCache
381 //To cache the pivot table data source
382 
383 sal_Bool ScDPTableDataCache::operator== ( const ScDPTableDataCache& r ) const
384 {
385     if ( GetColumnCount() == r.GetColumnCount() )
386     {
387         for ( SCCOL i = 0 ; i < GetColumnCount(); i++ )
388         {   //check dim names
389             if ( GetDimensionName( i ) != r.GetDimensionName( i ) )
390                 return sal_False;
391             //check rows count
392             if ( GetRowCount() != r.GetRowCount() )
393                 return sal_False;
394             //check dim member values
395             size_t nMembersCount = GetDimMemberValues( i ).size();
396             if ( GetDimMemberValues( i ).size() == r. GetDimMemberValues( i ).size() )
397             {
398                 for ( size_t j = 0; j < nMembersCount; j++ )
399                 {
400                     if ( *( GetDimMemberValues( i )[j] ) == *( r.GetDimMemberValues( i )[j] ) )
401                         continue;
402                     else
403                         return sal_False;
404                 }
405             }
406             else
407                 return sal_False;
408             //check source table index
409             for ( SCROW k=0 ; k < GetRowCount(); k ++ )
410             {
411                 if ( GetItemDataId( i, k, sal_False ) == r.GetItemDataId( i,k,sal_False) )
412                     continue;
413                 else
414                     return sal_False;
415             }
416         }
417     }
418     return sal_True;
419 }
420 
421 ScDPTableDataCache::ScDPTableDataCache(  ScDocument* pDoc  ) :
422 mpDoc( pDoc ),
423 mnColumnCount ( 0 ),
424 mpTableDataValues ( NULL ),
425 mpSourceData ( NULL ),
426 mpGlobalOrder( NULL ),
427 mpIndexOrder( NULL)
428 {
429     mnID = -1;
430 }
431 
432 ScDPTableDataCache::~ScDPTableDataCache()
433 {
434     if ( IsValid() )
435     {
436 // Wang Xu Ming -- 2/17/2009
437 // Performance issue
438         sal_uInt16 nCol;
439         for (  nCol=0; nCol < GetColumnCount() ; nCol++ )
440         {
441             for ( sal_uLong row = 0 ;  row < mpTableDataValues[nCol].size(); row++ )
442                 delete mpTableDataValues[nCol][row];
443         }
444         for ( nCol =0; nCol < mrLabelNames.size(); nCol++ )
445                 delete mrLabelNames[nCol];
446 // End Comments
447 
448         mnColumnCount = 0;
449         delete [] mpTableDataValues;
450         mpTableDataValues = NULL;
451         delete [] mpSourceData;
452         mpSourceData = NULL;
453         delete [] mpGlobalOrder;
454         mpGlobalOrder = NULL;
455         delete [] mpIndexOrder;
456         mpIndexOrder = NULL;
457     }
458 }
459 
460 // -----------------------------------------------------------------------
461 void ScDPTableDataCache::AddRow( ScDPItemData* pRow, sal_uInt16 nCount )
462 {
463     DBG_ASSERT( pRow , " empty pointer" );
464     if ( !mrLabelNames.size() )
465     {
466         mnColumnCount= nCount;
467         mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
468         mpSourceData      = new std::vector<SCROW>[ mnColumnCount ];
469         mpGlobalOrder     = new std::vector<SCROW>[ mnColumnCount ];
470         mpIndexOrder      = new std::vector<SCROW>[ mnColumnCount ];
471 
472         for ( sal_uInt16 i = 0; i < nCount ; i ++ )
473             AddLabel( new ScDPItemData( pRow[i] ) );
474     }
475     else
476     {
477         for ( sal_uInt16 i = 0; i < nCount && i < mnColumnCount; i ++ )
478             AddData( i, new ScDPItemData( pRow[i] ) );
479     }
480 }
481 
482 // -----------------------------------------------------------------------
483 bool  ScDPTableDataCache::IsValid() const
484 { //TODO: continue check valid
485     return mpTableDataValues!=NULL && mpSourceData!= NULL && mnColumnCount>0;
486 }
487 
488 // -----------------------------------------------------------------------
489 
490 namespace {
491 
492 /**
493  * While the macro interpret level is incremented, the formula cells are
494  * (semi-)guaranteed to be interpreted.
495  */
496 class MacroInterpretIncrementer
497 {
498 public:
499     MacroInterpretIncrementer(ScDocument* pDoc) :
500         mpDoc(pDoc)
501     {
502         mpDoc->IncMacroInterpretLevel();
503     }
504     ~MacroInterpretIncrementer()
505     {
506         mpDoc->DecMacroInterpretLevel();
507     }
508 private:
509     ScDocument* mpDoc;
510 };
511 
512 }
513 
514 // -----------------------------------------------------------------------
515 bool ScDPTableDataCache::InitFromDoc(  ScDocument* pDoc, const ScRange& rRange )
516 {
517     // Make sure the formula cells within the data range are interpreted
518     // during this call, for this method may be called from the interpretation
519     // of GETPIVOTDATA, which disables nested formula interpretation without
520     // increasing the macro level.
521     MacroInterpretIncrementer aMacroInc(pDoc);
522 
523     //
524     SCROW nStartRow = rRange.aStart.Row();  // start of data
525     SCROW nEndRow = rRange.aEnd.Row();
526     sal_uInt16 nStartCol = rRange.aStart.Col();
527     sal_uInt16 nEndCol = rRange.aEnd.Col();
528     sal_uInt16 nDocTab = rRange.aStart.Tab();
529 
530     //init
531     long nOldColumCount = mnColumnCount;
532     mnColumnCount = nEndCol - nStartCol + 1;
533     if ( IsValid() )
534     {
535         for ( sal_uInt16 nCol=0; nCol < nOldColumCount ; nCol++ )
536         {
537             for ( sal_uLong row = 0 ;  row < mpTableDataValues[nCol].size(); row++ )
538                 delete mpTableDataValues[nCol][row];
539             delete mrLabelNames[nCol];
540         }
541         delete [] mpTableDataValues;
542         delete [] mpSourceData;
543         delete [] mpGlobalOrder;
544         delete [] mpIndexOrder;
545         mrLabelNames.clear();
546     }
547 
548     mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
549     mpSourceData      = new std::vector<SCROW>[ mnColumnCount ];
550     mpGlobalOrder     = new std::vector<SCROW>[ mnColumnCount ];
551     mpIndexOrder      = new std::vector<SCROW>[ mnColumnCount ];
552     pDoc->FillDPCache( this, nDocTab, nStartCol, nEndCol, nStartRow, nEndRow );
553     return sal_True;
554 }
555 
556 // -----------------------------------------------------------------------
557 bool ScDPTableDataCache::InitFromDataBase (const Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate)
558 {
559   if (!xRowSet.is())
560         // Dont' even waste time to go any further.
561         return false;
562     try
563     {
564         Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(xRowSet, UNO_QUERY_THROW);
565         Reference<sdbc::XResultSetMetaData> xMeta = xMetaSupp->getMetaData();
566         if (!xMeta.is())
567             return false;
568 
569     long nOldColumCount = mnColumnCount;
570     mnColumnCount = xMeta->getColumnCount();
571     if ( IsValid() )
572     {
573         for ( sal_uInt16 nCol=0; nCol < nOldColumCount ; nCol++ )
574         {
575             for ( sal_uLong row = 0 ;  row < mpTableDataValues[nCol].size(); row++ )
576                 delete mpTableDataValues[nCol][row];
577             delete mrLabelNames[nCol];
578         }
579         delete [] mpTableDataValues;
580         delete [] mpSourceData;
581         delete [] mpGlobalOrder;
582         delete [] mpIndexOrder;
583         mrLabelNames.clear();
584     }
585         // Get column titles and types.
586     mrLabelNames.reserve(mnColumnCount);
587     mpTableDataValues = new std::vector<ScDPItemData*>[ mnColumnCount ];
588     mpSourceData      = new std::vector<SCROW>[ mnColumnCount ];
589     mpGlobalOrder     = new std::vector<SCROW>[ mnColumnCount ];
590     mpIndexOrder      = new std::vector<SCROW>[ mnColumnCount ];
591 
592     std::vector<sal_Int32> aColTypes(mnColumnCount);
593 
594         for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol)
595         {
596             String aColTitle = xMeta->getColumnLabel(nCol+1);
597             aColTypes[nCol]  = xMeta->getColumnType(nCol+1);
598            AddLabel( new ScDPItemData( aColTitle) );
599         }
600 
601         // Now get the data rows.
602         Reference<sdbc::XRow> xRow(xRowSet, UNO_QUERY_THROW);
603         xRowSet->first();
604         do
605         {
606             for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol)
607             {
608                ScDPItemData * pNew =  lcl_GetItemValue( xRow, aColTypes[nCol], nCol+1, rNullDate );
609                 if ( pNew )
610                     AddData(  nCol , pNew );
611             }
612         }
613         while (xRowSet->next());
614 
615     xRowSet->beforeFirst();
616 
617     return true;
618     }
619     catch (const Exception&)
620     {
621         return false;
622     }
623 }
624 // -----------------------------------------------------------------------
625 sal_uLong ScDPTableDataCache::GetDimNumType( SCCOL nDim) const
626 {
627     DBG_ASSERT( IsValid(), "  IsValid() == false " );
628     DBG_ASSERT( nDim < mnColumnCount && nDim >=0, " dimention out of bound " );
629     if ( mpTableDataValues[nDim].size()==0 )
630         return NUMBERFORMAT_UNDEFINED;
631     else
632         return GetNumType(mpTableDataValues[nDim][0]->nNumFormat);
633 }
634 
635 // -----------------------------------------------------------------------
636 bool ScDPTableDataCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam, sal_Bool *pSpecial)
637 { //Copied and modified from ScTable::ValidQuery
638         if (!rParam.GetEntry(0).bDoQuery)
639             return sal_True;
640         sal_Bool    bMatchWholeCell = mpDoc->GetDocOptions().IsMatchWholeCell();
641 
642         //---------------------------------------------------------------
643 
644         const SCSIZE nFixedBools = 32;
645         sal_Bool aBool[nFixedBools];
646         sal_Bool aTest[nFixedBools];
647         SCSIZE nEntryCount = rParam.GetEntryCount();
648         sal_Bool* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new sal_Bool[nEntryCount] );
649         sal_Bool* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new sal_Bool[nEntryCount] );
650 
651         long    nPos = -1;
652         SCSIZE  i    = 0;
653         CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::GetCaseCollator() :
654             ScGlobal::GetCollator() );
655         ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ?
656             ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration());
657 
658         while ( (i < nEntryCount) && rParam.GetEntry(i).bDoQuery )
659         {
660             ScQueryEntry& rEntry = rParam.GetEntry(i);
661             // we can only handle one single direct query
662             // #i115431# nField in QueryParam is the sheet column, not the field within the source range
663             SCCOL nQueryCol = (SCCOL)rEntry.nField;
664             if ( nQueryCol < rParam.nCol1 )
665                 nQueryCol = rParam.nCol1;
666             if ( nQueryCol > rParam.nCol2 )
667                 nQueryCol = rParam.nCol2;
668             SCCOL nSourceField = nQueryCol - rParam.nCol1;
669             SCROW nId = GetItemDataId( nSourceField, nRow, sal_False );
670             const ScDPItemData* pCellData = GetItemDataById( nSourceField, nId );
671 
672             sal_Bool bOk = sal_False;
673             sal_Bool bTestEqual = sal_False;
674 
675             if ( pSpecial && pSpecial[i] )
676             {
677                 if (rEntry.nVal == SC_EMPTYFIELDS)
678                     bOk = ! pCellData->IsHasData();
679                 else // if (rEntry.nVal == SC_NONEMPTYFIELDS)
680                     bOk =  pCellData->IsHasData();
681             }
682             else if ( !rEntry.bQueryByString && pCellData->IsValue() )
683             {   // by Value
684                 double nCellVal = pCellData->GetValue();
685 
686                 switch (rEntry.eOp)
687                 {
688                     case SC_EQUAL :
689                         bOk = ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
690                         break;
691                     case SC_LESS :
692                         bOk = (nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
693                         break;
694                     case SC_GREATER :
695                         bOk = (nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
696                         break;
697                     case SC_LESS_EQUAL :
698                         bOk = (nCellVal < rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
699                         break;
700                     case SC_GREATER_EQUAL :
701                         bOk = (nCellVal > rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
702                         break;
703                     case SC_NOT_EQUAL :
704                         bOk = !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
705                         break;
706                                default:
707                                  bOk= sal_False;
708                                   break;
709                 }
710             }
711             else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
712                     || (rEntry.bQueryByString
713                         && pCellData->HasStringData() )
714                 )
715             {   // by String
716                 String  aCellStr = pCellData->GetString();
717 
718                 sal_Bool bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
719                     || (rEntry.eOp == SC_NOT_EQUAL)));
720                 sal_Bool bTestRegExp = sal_False;
721                 if ( bRealRegExp || bTestRegExp )
722                 {
723                     xub_StrLen nStart = 0;
724                     xub_StrLen nEnd   = aCellStr.Len();
725                     sal_Bool bMatch = (sal_Bool) rEntry.GetSearchTextPtr( rParam.bCaseSens )
726                         ->SearchFrwrd( aCellStr, &nStart, &nEnd );
727                     // from 614 on, nEnd is behind the found text
728                     if ( bMatch && bMatchWholeCell
729                             && (nStart != 0 || nEnd != aCellStr.Len()) )
730                         bMatch = sal_False;    // RegExp must match entire cell string
731                     if ( bRealRegExp )
732                         bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch);
733                     else
734                         bTestEqual = bMatch;
735                 }
736                 if ( !bRealRegExp )
737                 {
738                     if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL )
739                     {
740                         if ( bMatchWholeCell )
741                         {
742                                         bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr );
743                             //Added by zhaosz,for sodc_2702,20060808
744                             String aStr = *rEntry.pStr;//"f*"
745                             //modified by weihuaw,for SODC_16698
746                             //use another way to find "*" in aStr
747                             sal_Bool bHasStar = sal_False;
748                             xub_StrLen nIndex;
749                             if( ( nIndex = aStr.Search('*') ) != STRING_NOTFOUND )
750                                 bHasStar = sal_True;
751                             if(bHasStar && (nIndex>0))
752                             {
753                                 for(i=0;(i<nIndex) && (i< aCellStr.Len()) ; i++)
754                                 {
755                                     if(aCellStr.GetChar( (sal_uInt16)i ) == aStr.GetChar((sal_uInt16) i ))
756                                     {
757                                         bOk=1;
758                                     }
759                                     else
760                                     {
761                                         bOk=0;
762                                         break;
763                                     }
764                                 }
765                             }
766                             //end modified
767                             //Added end,20060808
768                         }
769                         else
770                         {
771                             ::com::sun::star::uno::Sequence< sal_Int32 > xOff;
772                             String aCell( pTransliteration->transliterate(
773                                 aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(),
774                                 &xOff ) );
775                             String aQuer( pTransliteration->transliterate(
776                                 *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(),
777                                 &xOff ) );
778                             bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND);
779                         }
780                         if ( rEntry.eOp == SC_NOT_EQUAL )
781                             bOk = !bOk;
782                     }
783                     else
784                     {   // use collator here because data was probably sorted
785                         sal_Int32 nCompare = pCollator->compareString(
786                             aCellStr, *rEntry.pStr );
787                         switch (rEntry.eOp)
788                         {
789                             case SC_LESS :
790                                 bOk = (nCompare < 0);
791                                 break;
792                             case SC_GREATER :
793                                 bOk = (nCompare > 0);
794                                 break;
795                             case SC_LESS_EQUAL :
796                                 bOk = (nCompare <= 0);
797                                 break;
798                             case SC_GREATER_EQUAL :
799                                 bOk = (nCompare >= 0);
800                                 break;
801                             case SC_NOT_EQUAL:
802                                 DBG_ASSERT( false , "SC_NOT_EQUAL");
803                                 break;
804                             case SC_TOPVAL:
805                             case SC_BOTVAL:
806                             case SC_TOPPERC:
807                             case SC_BOTPERC:
808                             default:
809                                 break;
810                         }
811                     }
812                 }
813             }
814 
815             if (nPos == -1)
816             {
817                 nPos++;
818                 pPasst[nPos] = bOk;
819                 pTest[nPos] = bTestEqual;
820             }
821             else
822             {
823                 if (rEntry.eConnect == SC_AND)
824                 {
825                     pPasst[nPos] = pPasst[nPos] && bOk;
826                     pTest[nPos] = pTest[nPos] && bTestEqual;
827                 }
828                 else
829                 {
830                     nPos++;
831                     pPasst[nPos] = bOk;
832                     pTest[nPos] = bTestEqual;
833                 }
834             }
835             i++;
836         }
837 
838         for ( long j=1; j <= nPos; j++ )
839         {
840             pPasst[0] = pPasst[0] || pPasst[j];
841             pTest[0] = pTest[0] || pTest[j];
842         }
843 
844         sal_Bool bRet = pPasst[0];
845         if ( pPasst != &aBool[0] )
846             delete [] pPasst;
847         if ( pTest != &aTest[0] )
848             delete [] pTest;
849 
850         return bRet;
851 }
852 
853 // -----------------------------------------------------------------------
854 bool ScDPTableDataCache::IsRowEmpty( SCROW nRow ) const
855 {
856     return  mbEmptyRow[ nRow ];
857 
858 }
859 
860 // -----------------------------------------------------------------------
861 bool ScDPTableDataCache::IsEmptyMember( SCROW nRow, sal_uInt16 nColumn ) const
862 {
863     return !GetItemDataById( nColumn, GetItemDataId( nColumn, nRow, sal_False ) )->IsHasData();
864 }
865 
866 sal_Bool ScDPTableDataCache::AddData(long nDim, ScDPItemData* pitemData, bool bCheckDate )
867 {
868     DBG_ASSERT( IsValid(), "  IsValid() == false " );
869     DBG_ASSERT( nDim < mnColumnCount && nDim >=0 , "dimension out of bound" );
870     SCROW nIndex = 0;
871 
872     sal_Bool    bInserted = sal_False;
873     if( true == bCheckDate)
874     pitemData->SetDate( lcl_isDate( GetNumType( pitemData->nNumFormat ) ) );
875     if ( !lcl_Search( mpTableDataValues[nDim], mpGlobalOrder[nDim], *pitemData, nIndex ) )
876     {
877         mpTableDataValues[nDim].push_back( pitemData );
878         mpGlobalOrder[nDim].insert( mpGlobalOrder[nDim].begin()+nIndex, mpTableDataValues[nDim].size()-1  );
879         DBG_ASSERT( (size_t) mpGlobalOrder[nDim][nIndex] == mpTableDataValues[nDim].size()-1 ,"ScDPTableDataCache::AddData ");
880         mpSourceData[nDim].push_back( mpTableDataValues[nDim].size()-1 );
881         bInserted = sal_True;
882     }
883     else
884         mpSourceData[nDim].push_back( mpGlobalOrder[nDim][nIndex] );
885 //init empty row tag
886     size_t  nCurRow = mpSourceData[nDim].size() -1 ;
887 
888     while ( mbEmptyRow.size() <= nCurRow )
889         mbEmptyRow.push_back( sal_True );
890 
891     if ( pitemData->IsHasData() )
892         mbEmptyRow[ nCurRow ] = sal_False;
893 
894     if ( !bInserted )
895         delete pitemData;
896 
897     return sal_True;
898 }
899 
900 String ScDPTableDataCache::GetDimensionName( sal_uInt16 nColumn ) const
901 {
902     DBG_ASSERT( /* nColumn>=0 && */ nColumn < mrLabelNames.size()-1 , "ScDPTableDataCache::GetDimensionName");
903     DBG_ASSERT( mrLabelNames.size() == static_cast <sal_uInt16> (mnColumnCount+1), "ScDPTableDataCache::GetDimensionName");
904     if ( static_cast<size_t>(nColumn+1) < mrLabelNames.size() )
905     {
906         return mrLabelNames[nColumn+1]->aString;
907     }
908     else
909         return String();
910 }
911 
912 
913 void ScDPTableDataCache::AddLabel(ScDPItemData *pData)
914 {
915     DBG_ASSERT( IsValid(), "  IsValid() == false " );
916 
917     if ( mrLabelNames.size() == 0 )
918         mrLabelNames.push_back( new ScDPItemData(  ScGlobal::GetRscString(STR_PIVOT_DATA) ) );
919 
920 
921     //reset name if needed
922     String strNewName = pData->aString;
923 
924     // #i116457# don't modify empty column titles
925     if ( strNewName.Len() )
926     {
927         sal_Bool bFound = sal_False;
928         long nIndex = 1;
929         do
930         {
931             for ( long i= mrLabelNames.size()-1; i>=0; i-- )
932             {
933                 if( mrLabelNames[i]->aString == strNewName )
934                 {
935                     strNewName  =  pData->aString;
936                     strNewName += String::CreateFromInt32( nIndex );
937                     nIndex ++ ;
938                     bFound = sal_True;
939                 }
940             }
941             bFound = !bFound;
942         }
943         while ( !bFound );
944     }
945 
946     pData->aString = strNewName;
947     mrLabelNames.push_back( pData );
948 }
949 
950 SCROW ScDPTableDataCache::GetItemDataId(sal_uInt16 nDim, SCROW nRow, sal_Bool bRepeatIfEmpty) const
951 { //
952     DBG_ASSERT( IsValid(), "  IsValid() == false " );
953     DBG_ASSERT( /* nDim >= 0 && */ nDim < mnColumnCount, "ScDPTableDataCache::GetItemDataId " );
954 
955     if ( bRepeatIfEmpty )
956     {
957         while ( nRow >0 && !mpTableDataValues[nDim][ mpSourceData[nDim][nRow] ]->IsHasData() )
958         --nRow;
959     }
960 
961     return mpSourceData[nDim][nRow];
962 }
963 
964 const ScDPItemData* ScDPTableDataCache::GetItemDataById(long nDim, SCROW nId) const
965 {
966     if ( nId >= GetRowCount()  )
967         return maAdditionalDatas.getData( nId - GetRowCount() );
968 
969     if (  (size_t)nId >= mpTableDataValues[nDim].size() || nDim >= mnColumnCount  || nId < 0  )
970         return NULL;
971     else
972         return mpTableDataValues[nDim][nId];
973 }
974 
975 SCROW ScDPTableDataCache::GetRowCount() const
976 {
977     if ( IsValid() )
978         return mpSourceData[0].size();
979     else
980         return 0;
981 }
982 
983 const std::vector<ScDPItemData*>& ScDPTableDataCache::GetDimMemberValues(SCCOL nDim) const
984 {
985     DBG_ASSERT( nDim>=0 && nDim < mnColumnCount ," nDim < mnColumnCount ");
986     return mpTableDataValues[nDim];
987 }
988 
989 SCROW ScDPTableDataCache::GetSortedItemDataId(SCCOL nDim, SCROW nOrder) const
990 {
991     DBG_ASSERT ( IsValid(), "IsValid");
992     DBG_ASSERT( nDim>=0 && nDim < mnColumnCount,  "nDim < mnColumnCount");
993     DBG_ASSERT( nOrder >= 0 && (size_t) nOrder < mpGlobalOrder[nDim].size(), "nOrder < mpGlobalOrder[nDim].size()" );
994 
995     return mpGlobalOrder[nDim][nOrder];
996 }
997 
998 sal_uLong ScDPTableDataCache::GetNumType(sal_uLong nFormat) const
999 {
1000     SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
1001     sal_uLong nType = NUMBERFORMAT_NUMBER;
1002     if ( pFormatter )
1003         nType = pFormatter->GetType( nFormat );
1004     return nType;
1005 }
1006 
1007 sal_uLong ScDPTableDataCache::GetNumberFormat( long nDim ) const
1008 {
1009     if ( nDim >= mnColumnCount )
1010         return 0;
1011 
1012     // #i113411# take the number format from the first value entry
1013     size_t nSize = mpTableDataValues[nDim].size();
1014     size_t nPos = 0;
1015     while ( nPos < nSize && mpTableDataValues[nDim][nPos]->GetType() != SC_VALTYPE_VALUE )
1016         ++nPos;
1017     if ( nPos < nSize )
1018         return mpTableDataValues[nDim][nPos]->nNumFormat;
1019     return 0;
1020 }
1021 
1022 sal_Bool ScDPTableDataCache::IsDateDimension( long nDim ) const
1023 {
1024     if ( nDim >= mnColumnCount )
1025         return false;
1026     else if ( mpTableDataValues[nDim].size()==0 )
1027         return false;
1028     else
1029         return mpTableDataValues[nDim][0]->IsDate();
1030 
1031 }
1032 
1033 SCROW ScDPTableDataCache::GetDimMemberCount( SCCOL nDim ) const
1034 {
1035     DBG_ASSERT( nDim>=0 && nDim < mnColumnCount ," ScDPTableDataCache::GetDimMemberCount : out of bound ");
1036     return mpTableDataValues[nDim].size();
1037 }
1038 
1039 const ScDPItemData* ScDPTableDataCache::GetSortedItemData(SCCOL nDim, SCROW nOrder) const
1040 {
1041     SCROW n = GetSortedItemDataId( nDim, nOrder );
1042     return GetItemDataById( nDim, n );
1043 }
1044 
1045 SCCOL ScDPTableDataCache::GetDimensionIndex(String sName) const
1046 {
1047     for ( size_t n = 1; n < mrLabelNames.size(); n ++ ) //defects, label name map wrong SODC_17590, SODC_18932,SODC_18827,SODC_18960,SODC_18923
1048     {
1049         if ( mrLabelNames[n]->GetString() == sName )
1050             return (SCCOL)(n-1);
1051     }
1052     return -1;
1053 }
1054 
1055 SCROW ScDPTableDataCache::GetIdByItemData(long nDim, String sItemData ) const
1056 {
1057     if ( nDim < mnColumnCount && nDim >=0 )
1058     {
1059         for ( size_t n = 0; n< mpTableDataValues[nDim].size(); n++ )
1060         {
1061             if ( mpTableDataValues[nDim][n]->GetString() == sItemData )
1062                 return n;
1063         }
1064     }
1065 
1066     ScDPItemData rData ( sItemData );
1067     return  GetRowCount() +maAdditionalDatas.getDataId(rData);
1068 }
1069 
1070 SCROW ScDPTableDataCache::GetIdByItemData( long nDim, const ScDPItemData& rData  ) const
1071 {
1072     if ( nDim < mnColumnCount && nDim >=0 )
1073     {
1074         for ( size_t n = 0; n< mpTableDataValues[nDim].size(); n++ )
1075         {
1076             if ( *mpTableDataValues[nDim][n] == rData )
1077                 return n;
1078         }
1079     }
1080     return  GetRowCount() + maAdditionalDatas.getDataId(rData);
1081 }
1082 
1083 SCROW ScDPTableDataCache::GetAdditionalItemID ( String sItemData )
1084 {
1085     ScDPItemData rData ( sItemData );
1086     return GetAdditionalItemID( rData );
1087 }
1088 
1089 SCROW ScDPTableDataCache::GetAdditionalItemID( const ScDPItemData& rData )
1090 {
1091     return GetRowCount() + maAdditionalDatas.insertData( rData );
1092 }
1093 
1094 
1095 SCROW ScDPTableDataCache::GetOrder(long nDim, SCROW nIndex) const
1096 {
1097     DBG_ASSERT( IsValid(), "  IsValid() == false " );
1098     DBG_ASSERT( nDim >=0 && nDim < mnColumnCount, "ScDPTableDataCache::GetOrder : out of bound" );
1099 
1100     if ( mpIndexOrder[nDim].size() !=  mpGlobalOrder[nDim].size() )
1101     { //not inited
1102         SCROW i  = 0;
1103         mpIndexOrder[nDim].resize(  mpGlobalOrder[nDim].size(), 0 );
1104         for ( size_t n = 0 ; n<  mpGlobalOrder[nDim].size(); n++ )
1105         {
1106             i =  mpGlobalOrder[nDim][n];
1107             mpIndexOrder[nDim][ i ] = n;
1108         }
1109     }
1110 
1111     DBG_ASSERT( nIndex>=0 && (size_t)nIndex < mpIndexOrder[nDim].size() , "ScDPTableDataCache::GetOrder");
1112     return  mpIndexOrder[nDim][nIndex];
1113 }
1114 
1115 ScDocument*  ScDPTableDataCache::GetDoc() const
1116 {
1117     return mpDoc;
1118 };
1119 
1120 long ScDPTableDataCache::GetColumnCount() const
1121 {
1122     return mnColumnCount;
1123 }
1124 long    ScDPTableDataCache::GetId() const
1125 {
1126     return mnID;
1127 }
1128