xref: /aoo42x/main/sc/source/core/data/dptablecache.cxx (revision 7a6646f1)
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