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