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