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