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