1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_connectivity.hxx" 30 31 #include <ctype.h> 32 #include "flat/ETable.hxx" 33 #include <com/sun/star/sdbc/ColumnValue.hpp> 34 #include <com/sun/star/sdbc/DataType.hpp> 35 #include <com/sun/star/ucb/XContentAccess.hpp> 36 #include <svl/converter.hxx> 37 #include "flat/EConnection.hxx" 38 #include "flat/EColumns.hxx" 39 #include <osl/thread.h> 40 #include <tools/config.hxx> 41 #include <comphelper/sequence.hxx> 42 #include <svl/zforlist.hxx> 43 #include <rtl/math.hxx> 44 #include <stdio.h> //sprintf 45 #include <comphelper/extract.hxx> 46 #include <comphelper/numbers.hxx> 47 #include "flat/EDriver.hxx" 48 #include <com/sun/star/util/NumberFormat.hpp> 49 #include <unotools/configmgr.hxx> 50 #include <i18npool/mslangid.hxx> 51 #include "connectivity/dbconversion.hxx" 52 #include <comphelper/types.hxx> 53 #include "file/quotedstring.hxx" 54 #include <unotools/syslocale.hxx> 55 #include <rtl/logfile.hxx> 56 57 using namespace ::comphelper; 58 using namespace connectivity; 59 using namespace connectivity::flat; 60 using namespace connectivity::file; 61 using namespace ::cppu; 62 using namespace utl; 63 using namespace ::com::sun::star::uno; 64 using namespace ::com::sun::star::ucb; 65 using namespace ::com::sun::star::beans; 66 using namespace ::com::sun::star::sdbcx; 67 using namespace ::com::sun::star::sdbc; 68 using namespace ::com::sun::star::container; 69 using namespace ::com::sun::star::lang; 70 71 // ------------------------------------------------------------------------- 72 void OFlatTable::fillColumns(const ::com::sun::star::lang::Locale& _aLocale) 73 { 74 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::fillColumns" ); 75 sal_Bool bRead = sal_True; 76 77 QuotedTokenizedString aHeaderLine; 78 OFlatConnection* pConnection = (OFlatConnection*)m_pConnection; 79 const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding(); 80 const sal_Bool bHasHeaderLine = pConnection->isHeaderLine(); 81 if ( bHasHeaderLine ) 82 { 83 while(bRead && !aHeaderLine.Len()) 84 { 85 bRead = m_pFileStream->ReadByteStringLine(aHeaderLine,nEncoding); 86 } 87 m_nStartRowFilePos = m_pFileStream->Tell(); 88 } 89 90 // read first row 91 QuotedTokenizedString aFirstLine; 92 bRead = m_pFileStream->ReadByteStringLine(aFirstLine,nEncoding); 93 94 if ( !bHasHeaderLine || !aHeaderLine.Len()) 95 { 96 while(bRead && !aFirstLine.Len()) 97 { 98 bRead = m_pFileStream->ReadByteStringLine(aFirstLine,nEncoding); 99 } 100 // use first row as headerline because we need the number of columns 101 aHeaderLine = aFirstLine; 102 } 103 // column count 104 const xub_StrLen nFieldCount = aHeaderLine.GetTokenCount(m_cFieldDelimiter,m_cStringDelimiter); 105 106 if(!m_aColumns.isValid()) 107 m_aColumns = new OSQLColumns(); 108 else 109 m_aColumns->get().clear(); 110 111 m_aTypes.clear(); 112 m_aPrecisions.clear(); 113 m_aScales.clear(); 114 // reserve some space 115 m_aColumns->get().reserve(nFieldCount+1); 116 m_aTypes.assign(nFieldCount+1,DataType::SQLNULL); 117 m_aPrecisions.assign(nFieldCount+1,-1); 118 m_aScales.assign(nFieldCount+1,-1); 119 120 const sal_Bool bCase = m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers(); 121 CharClass aCharClass(pConnection->getDriver()->getFactory(),_aLocale); 122 // read description 123 const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); 124 const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); 125 String aColumnName; 126 ::rtl::OUString aTypeName; 127 ::comphelper::UStringMixEqual aCase(bCase); 128 ::std::vector<String> aColumnNames,m_aTypeNames; 129 m_aTypeNames.resize(nFieldCount); 130 const sal_Int32 nMaxRowsToScan = pConnection->getMaxRowsToScan(); 131 sal_Int32 nRowCount = 0; 132 do 133 { 134 xub_StrLen nStartPosHeaderLine = 0; // use for eficient way to get the tokens 135 xub_StrLen nStartPosFirstLine = 0; // use for eficient way to get the tokens 136 xub_StrLen nStartPosFirstLine2 = 0; 137 for (xub_StrLen i = 0; i < nFieldCount; i++) 138 { 139 if ( nRowCount == 0) 140 { 141 if ( bHasHeaderLine ) 142 { 143 aHeaderLine.GetTokenSpecial(aColumnName,nStartPosHeaderLine,m_cFieldDelimiter,m_cStringDelimiter); 144 if ( !aColumnName.Len() ) 145 { 146 aColumnName = 'C'; 147 aColumnName += String::CreateFromInt32(i+1); 148 } 149 } 150 else 151 { 152 // no column name so ... 153 aColumnName = 'C'; 154 aColumnName += String::CreateFromInt32(i+1); 155 } 156 aColumnNames.push_back(aColumnName); 157 } 158 impl_fillColumnInfo_nothrow(aFirstLine,nStartPosFirstLine,nStartPosFirstLine2,m_aTypes[i],m_aPrecisions[i],m_aScales[i],m_aTypeNames[i],cDecimalDelimiter,cThousandDelimiter,aCharClass); 159 } 160 ++nRowCount; 161 } 162 while(nRowCount < nMaxRowsToScan && m_pFileStream->ReadByteStringLine(aFirstLine,nEncoding) && !m_pFileStream->IsEof()); 163 164 for (xub_StrLen i = 0; i < nFieldCount; i++) 165 { 166 // check if the columname already exists 167 String aAlias(aColumnNames[i]); 168 OSQLColumns::Vector::const_iterator aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase); 169 sal_Int32 nExprCnt = 0; 170 while(aFind != m_aColumns->get().end()) 171 { 172 (aAlias = aColumnNames[i]) += String::CreateFromInt32(++nExprCnt); 173 aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase); 174 } 175 176 sdbcx::OColumn* pColumn = new sdbcx::OColumn(aAlias,m_aTypeNames[i],::rtl::OUString(),::rtl::OUString(), 177 ColumnValue::NULLABLE, 178 m_aPrecisions[i], 179 m_aScales[i], 180 m_aTypes[i], 181 sal_False, 182 sal_False, 183 sal_False, 184 bCase); 185 Reference< XPropertySet> xCol = pColumn; 186 m_aColumns->get().push_back(xCol); 187 } 188 m_pFileStream->Seek(m_nStartRowFilePos); 189 } 190 void OFlatTable::impl_fillColumnInfo_nothrow(QuotedTokenizedString& aFirstLine,xub_StrLen& nStartPosFirstLine,xub_StrLen& nStartPosFirstLine2 191 ,sal_Int32& io_nType,sal_Int32& io_nPrecisions,sal_Int32& io_nScales,String& o_sTypeName 192 ,const sal_Unicode cDecimalDelimiter,const sal_Unicode cThousandDelimiter,const CharClass& aCharClass) 193 { 194 if ( io_nType != DataType::VARCHAR ) 195 { 196 sal_Bool bNumeric = io_nType == DataType::SQLNULL || io_nType == DataType::DOUBLE || io_nType == DataType::DECIMAL || io_nType == DataType::INTEGER; 197 sal_uLong nIndex = 0; 198 199 if ( bNumeric ) 200 { 201 // first without fielddelimiter 202 String aField; 203 aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); 204 if (aField.Len() == 0 || 205 (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) 206 { 207 bNumeric = sal_False; 208 if ( m_cStringDelimiter != '\0' ) 209 aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); 210 else 211 nStartPosFirstLine2 = nStartPosFirstLine; 212 } 213 else 214 { 215 String aField2; 216 if ( m_cStringDelimiter != '\0' ) 217 aFirstLine.GetTokenSpecial(aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); 218 else 219 aField2 = aField; 220 221 if (aField2.Len() == 0) 222 { 223 bNumeric = sal_False; 224 } 225 else 226 { 227 bNumeric = sal_True; 228 xub_StrLen nDot = 0; 229 xub_StrLen nDecimalDelCount = 0; 230 xub_StrLen nSpaceCount = 0; 231 for (xub_StrLen j = 0; j < aField2.Len(); j++) 232 { 233 const sal_Unicode c = aField2.GetChar(j); 234 if ( j == nSpaceCount && m_cFieldDelimiter != 32 && c == 32 ) 235 { 236 ++nSpaceCount; 237 continue; 238 } 239 // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen? 240 if ( ( !cDecimalDelimiter || c != cDecimalDelimiter ) && 241 ( !cThousandDelimiter || c != cThousandDelimiter ) && 242 !aCharClass.isDigit(aField2,j) && 243 ( j != 0 || (c != '+' && c != '-' ) ) ) 244 { 245 bNumeric = sal_False; 246 break; 247 } 248 if (cDecimalDelimiter && c == cDecimalDelimiter) 249 { 250 io_nPrecisions = 15; // we have an decimal value 251 io_nScales = 2; 252 ++nDecimalDelCount; 253 } // if (cDecimalDelimiter && c == cDecimalDelimiter) 254 if ( c == '.' ) 255 ++nDot; 256 } 257 258 if (nDecimalDelCount > 1 || nDot > 1 ) // if there is more than one dot it isn't a number 259 bNumeric = sal_False; 260 if (bNumeric && cThousandDelimiter) 261 { 262 // Ist der Trenner richtig angegeben? 263 const String aValue = aField2.GetToken(0,cDecimalDelimiter); 264 for (sal_Int32 j = aValue.Len() - 4; j >= 0; j -= 4) 265 { 266 const sal_Unicode c = aValue.GetChar(static_cast<sal_uInt16>(j)); 267 // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen? 268 if (c == cThousandDelimiter && j) 269 continue; 270 else 271 { 272 bNumeric = sal_False; 273 break; 274 } 275 } 276 } 277 278 // jetzt koennte es noch ein Datumsfeld sein 279 if (!bNumeric) 280 { 281 try 282 { 283 nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2); 284 } 285 catch(Exception&) 286 { 287 } 288 } 289 } 290 } 291 } 292 else if ( io_nType == DataType::DATE || io_nType == DataType::TIMESTAMP || io_nType == DataType::TIME) 293 { 294 String aField; 295 aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); 296 if (aField.Len() == 0 || 297 (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) 298 { 299 } 300 else 301 { 302 String aField2; 303 if ( m_cStringDelimiter != '\0' ) 304 aFirstLine.GetTokenSpecial(aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); 305 else 306 aField2 = aField; 307 if (aField2.Len() ) 308 { 309 try 310 { 311 nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2); 312 } 313 catch(Exception&) 314 { 315 } 316 } 317 } 318 } 319 320 sal_Int32 nFlags = 0; 321 if (bNumeric) 322 { 323 if (cDecimalDelimiter) 324 { 325 if(io_nPrecisions) 326 { 327 io_nType = DataType::DECIMAL; 328 static const ::rtl::OUString s_sDECIMAL(RTL_CONSTASCII_USTRINGPARAM("DECIMAL")); 329 o_sTypeName = s_sDECIMAL; 330 } 331 else 332 { 333 io_nType = DataType::DOUBLE; 334 static const ::rtl::OUString s_sDOUBLE(RTL_CONSTASCII_USTRINGPARAM("DOUBLE")); 335 o_sTypeName = s_sDOUBLE; 336 } 337 } 338 else 339 { 340 io_nType = DataType::INTEGER; 341 io_nPrecisions = 0; 342 io_nScales = 0; 343 } 344 nFlags = ColumnSearch::BASIC; 345 } 346 else 347 { 348 switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex)) 349 { 350 case NUMBERFORMAT_DATE: 351 io_nType = DataType::DATE; 352 { 353 static const ::rtl::OUString s_sDATE(RTL_CONSTASCII_USTRINGPARAM("DATE")); 354 o_sTypeName = s_sDATE; 355 } 356 break; 357 case NUMBERFORMAT_DATETIME: 358 io_nType = DataType::TIMESTAMP; 359 { 360 static const ::rtl::OUString s_sTIMESTAMP(RTL_CONSTASCII_USTRINGPARAM("TIMESTAMP")); 361 o_sTypeName = s_sTIMESTAMP; 362 } 363 break; 364 case NUMBERFORMAT_TIME: 365 io_nType = DataType::TIME; 366 { 367 static const ::rtl::OUString s_sTIME(RTL_CONSTASCII_USTRINGPARAM("TIME")); 368 o_sTypeName = s_sTIME; 369 } 370 break; 371 default: 372 io_nType = DataType::VARCHAR; 373 io_nPrecisions = 0; // nyi: Daten koennen aber laenger sein! 374 io_nScales = 0; 375 { 376 static const ::rtl::OUString s_sVARCHAR(RTL_CONSTASCII_USTRINGPARAM("VARCHAR")); 377 o_sTypeName = s_sVARCHAR; 378 } 379 }; 380 nFlags |= ColumnSearch::CHAR; 381 } 382 } 383 else 384 { 385 String aField; 386 aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine,m_cFieldDelimiter,'\0'); 387 if (aField.Len() == 0 || 388 (m_cStringDelimiter && m_cStringDelimiter == aField.GetChar(0))) 389 { 390 if ( m_cStringDelimiter != '\0' ) 391 aFirstLine.GetTokenSpecial(aField,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); 392 else 393 nStartPosFirstLine2 = nStartPosFirstLine; 394 } 395 else 396 { 397 String aField2; 398 if ( m_cStringDelimiter != '\0' ) 399 aFirstLine.GetTokenSpecial(aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); 400 } 401 } 402 } 403 // ------------------------------------------------------------------------- 404 OFlatTable::OFlatTable(sdbcx::OCollection* _pTables,OFlatConnection* _pConnection, 405 const ::rtl::OUString& _Name, 406 const ::rtl::OUString& _Type, 407 const ::rtl::OUString& _Description , 408 const ::rtl::OUString& _SchemaName, 409 const ::rtl::OUString& _CatalogName 410 ) : OFlatTable_BASE(_pTables,_pConnection,_Name, 411 _Type, 412 _Description, 413 _SchemaName, 414 _CatalogName) 415 ,m_nStartRowFilePos(0) 416 ,m_nRowPos(0) 417 ,m_nMaxRowCount(0) 418 ,m_cStringDelimiter(_pConnection->getStringDelimiter()) 419 ,m_cFieldDelimiter(_pConnection->getFieldDelimiter()) 420 ,m_bNeedToReadLine(false) 421 { 422 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::OFlatTable" ); 423 424 } 425 // ----------------------------------------------------------------------------- 426 void OFlatTable::construct() 427 { 428 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::construct" ); 429 SvtSysLocale aLocale; 430 ::com::sun::star::lang::Locale aAppLocale(aLocale.GetLocaleDataPtr()->getLocale()); 431 Sequence< ::com::sun::star::uno::Any > aArg(1); 432 aArg[0] <<= aAppLocale; 433 434 Reference< ::com::sun::star::util::XNumberFormatsSupplier > xSupplier(m_pConnection->getDriver()->getFactory()->createInstanceWithArguments(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatsSupplier"),aArg),UNO_QUERY); 435 m_xNumberFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(m_pConnection->getDriver()->getFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatter")),UNO_QUERY); 436 m_xNumberFormatter->attachNumberFormatsSupplier(xSupplier); 437 Reference<XPropertySet> xProp(xSupplier->getNumberFormatSettings(),UNO_QUERY); 438 xProp->getPropertyValue(::rtl::OUString::createFromAscii("NullDate")) >>= m_aNullDate; 439 440 INetURLObject aURL; 441 aURL.SetURL(getEntry()); 442 443 if(aURL.getExtension() != rtl::OUString(m_pConnection->getExtension())) 444 aURL.setExtension(m_pConnection->getExtension()); 445 446 String aFileName = aURL.GetMainURL(INetURLObject::NO_DECODE); 447 448 m_pFileStream = createStream_simpleError( aFileName,STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYWRITE); 449 450 if(!m_pFileStream) 451 m_pFileStream = createStream_simpleError( aFileName,STREAM_READ | STREAM_NOCREATE | STREAM_SHARE_DENYNONE); 452 453 if(m_pFileStream) 454 { 455 m_pFileStream->Seek(STREAM_SEEK_TO_END); 456 sal_Int32 nSize = m_pFileStream->Tell(); 457 m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN); 458 459 // Buffersize abhaengig von der Filegroesse 460 m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 : 461 nSize > 100000 ? 16384 : 462 nSize > 10000 ? 4096 : 1024); 463 464 fillColumns(aAppLocale); 465 466 refreshColumns(); 467 } 468 } 469 // ------------------------------------------------------------------------- 470 String OFlatTable::getEntry() 471 { 472 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::getEntry" ); 473 ::rtl::OUString sURL; 474 try 475 { 476 Reference< XResultSet > xDir = m_pConnection->getDir()->getStaticResultSet(); 477 Reference< XRow> xRow(xDir,UNO_QUERY); 478 ::rtl::OUString sName; 479 ::rtl::OUString sExt; 480 481 INetURLObject aURL; 482 xDir->beforeFirst(); 483 static const ::rtl::OUString s_sSeparator(RTL_CONSTASCII_USTRINGPARAM("/")); 484 while(xDir->next()) 485 { 486 sName = xRow->getString(1); 487 aURL.SetSmartProtocol(INET_PROT_FILE); 488 String sUrl = m_pConnection->getURL() + s_sSeparator + sName; 489 aURL.SetSmartURL( sUrl ); 490 491 // cut the extension 492 sExt = aURL.getExtension(); 493 494 // name and extension have to coincide 495 if ( m_pConnection->matchesExtension( sExt ) ) 496 { 497 if ( sExt.getLength() ) 498 sName = sName.replaceAt(sName.getLength()-(sExt.getLength()+1),sExt.getLength()+1,::rtl::OUString()); 499 if ( sName == m_Name ) 500 { 501 Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY ); 502 sURL = xContentAccess->queryContentIdentifierString(); 503 break; 504 } 505 } 506 } 507 xDir->beforeFirst(); // move back to before first record 508 } 509 catch(Exception&) 510 { 511 OSL_ASSERT(0); 512 } 513 return sURL.getStr(); 514 } 515 // ------------------------------------------------------------------------- 516 void OFlatTable::refreshColumns() 517 { 518 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::refreshColumns" ); 519 ::osl::MutexGuard aGuard( m_aMutex ); 520 521 TStringVector aVector; 522 aVector.reserve(m_aColumns->get().size()); 523 524 for(OSQLColumns::Vector::const_iterator aIter = m_aColumns->get().begin();aIter != m_aColumns->get().end();++aIter) 525 aVector.push_back(Reference< XNamed>(*aIter,UNO_QUERY)->getName()); 526 527 if(m_pColumns) 528 m_pColumns->reFill(aVector); 529 else 530 m_pColumns = new OFlatColumns(this,m_aMutex,aVector); 531 } 532 533 // ------------------------------------------------------------------------- 534 void SAL_CALL OFlatTable::disposing(void) 535 { 536 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::disposing" ); 537 OFileTable::disposing(); 538 ::osl::MutexGuard aGuard(m_aMutex); 539 m_aColumns = NULL; 540 } 541 // ------------------------------------------------------------------------- 542 Sequence< Type > SAL_CALL OFlatTable::getTypes( ) throw(RuntimeException) 543 { 544 Sequence< Type > aTypes = OTable_TYPEDEF::getTypes(); 545 ::std::vector<Type> aOwnTypes; 546 aOwnTypes.reserve(aTypes.getLength()); 547 const Type* pBegin = aTypes.getConstArray(); 548 const Type* pEnd = pBegin + aTypes.getLength(); 549 for(;pBegin != pEnd;++pBegin) 550 { 551 if(!(*pBegin == ::getCppuType((const Reference<XKeysSupplier>*)0) || 552 *pBegin == ::getCppuType((const Reference<XRename>*)0) || 553 *pBegin == ::getCppuType((const Reference<XIndexesSupplier>*)0) || 554 *pBegin == ::getCppuType((const Reference<XAlterTable>*)0) || 555 *pBegin == ::getCppuType((const Reference<XDataDescriptorFactory>*)0))) 556 { 557 aOwnTypes.push_back(*pBegin); 558 } 559 } 560 Type *pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0]; 561 return Sequence< Type >(pTypes, aOwnTypes.size()); 562 } 563 564 // ------------------------------------------------------------------------- 565 Any SAL_CALL OFlatTable::queryInterface( const Type & rType ) throw(RuntimeException) 566 { 567 if( rType == ::getCppuType((const Reference<XKeysSupplier>*)0) || 568 rType == ::getCppuType((const Reference<XIndexesSupplier>*)0) || 569 rType == ::getCppuType((const Reference<XRename>*)0) || 570 rType == ::getCppuType((const Reference<XAlterTable>*)0) || 571 rType == ::getCppuType((const Reference<XDataDescriptorFactory>*)0)) 572 return Any(); 573 574 Any aRet = OTable_TYPEDEF::queryInterface(rType); 575 return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< ::com::sun::star::lang::XUnoTunnel*> (this)); 576 } 577 578 //-------------------------------------------------------------------------- 579 Sequence< sal_Int8 > OFlatTable::getUnoTunnelImplementationId() 580 { 581 static ::cppu::OImplementationId * pId = 0; 582 if (! pId) 583 { 584 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); 585 if (! pId) 586 { 587 static ::cppu::OImplementationId aId; 588 pId = &aId; 589 } 590 } 591 return pId->getImplementationId(); 592 } 593 594 // com::sun::star::lang::XUnoTunnel 595 //------------------------------------------------------------------ 596 sal_Int64 OFlatTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException) 597 { 598 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::getSomething" ); 599 return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) ) 600 ? reinterpret_cast< sal_Int64 >( this ) 601 : OFlatTable_BASE::getSomething(rId); 602 } 603 //------------------------------------------------------------------ 604 sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal_Bool bIsTable,sal_Bool bRetrieveData) 605 { 606 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::fetchRow" ); 607 *(_rRow->get())[0] = m_nFilePos; 608 609 if (!bRetrieveData) 610 return sal_True; 611 if ( m_bNeedToReadLine ) 612 { 613 sal_Int32 nCurrentPos = 0; 614 m_pFileStream->Seek(m_nFilePos); 615 readLine(nCurrentPos); 616 m_bNeedToReadLine = false; 617 } 618 619 OFlatConnection* pConnection = (OFlatConnection*)m_pConnection; 620 const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); 621 const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); 622 // Felder: 623 xub_StrLen nStartPos = 0; 624 String aStr; 625 OSQLColumns::Vector::const_iterator aIter = _rCols.get().begin(); 626 OSQLColumns::Vector::const_iterator aEnd = _rCols.get().end(); 627 const OValueRefVector::Vector::size_type nCount = _rRow->get().size(); 628 for (OValueRefVector::Vector::size_type i = 1; aIter != aEnd && i < nCount; 629 ++aIter, i++) 630 { 631 m_aCurrentLine.GetTokenSpecial(aStr,nStartPos,m_cFieldDelimiter,m_cStringDelimiter); 632 633 if (aStr.Len() == 0) 634 (_rRow->get())[i]->setNull(); 635 else 636 { 637 // Laengen je nach Datentyp: 638 sal_Int32 nLen, 639 nType = 0; 640 if(bIsTable) 641 { 642 nLen = m_aPrecisions[i-1]; 643 nType = m_aTypes[i-1]; 644 } 645 else 646 { 647 Reference< XPropertySet> xColumn = *aIter; 648 xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nLen; 649 xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType; 650 } 651 switch(nType) 652 { 653 case DataType::TIMESTAMP: 654 case DataType::DATE: 655 case DataType::TIME: 656 { 657 try 658 { 659 double nRes = m_xNumberFormatter->convertStringToNumber(::com::sun::star::util::NumberFormat::ALL,aStr); 660 661 switch(nType) 662 { 663 case DataType::DATE: 664 *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes,m_aNullDate)); 665 break; 666 case DataType::TIMESTAMP: 667 *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes,m_aNullDate)); 668 break; 669 default: 670 *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes)); 671 } 672 } 673 catch(Exception&) 674 { 675 (_rRow->get())[i]->setNull(); 676 } 677 } break; 678 case DataType::DOUBLE: 679 case DataType::INTEGER: 680 case DataType::DECIMAL: // #99178# OJ 681 case DataType::NUMERIC: 682 { 683 684 String aStrConverted; 685 if ( DataType::INTEGER != nType ) 686 { 687 sal_Unicode* pData = aStrConverted.AllocBuffer(aStr.Len()); 688 const sal_Unicode* pStart = pData; 689 690 OSL_ENSURE(cDecimalDelimiter && nType != DataType::INTEGER || 691 !cDecimalDelimiter && nType == DataType::INTEGER, 692 "FalscherTyp"); 693 694 // In Standard-Notation (DezimalPUNKT ohne Tausender-Komma) umwandeln: 695 for (xub_StrLen j = 0; j < aStr.Len(); ++j) 696 { 697 const sal_Unicode cChar = aStr.GetChar(j); 698 if (cDecimalDelimiter && cChar == cDecimalDelimiter) 699 *pData++ = '.'; 700 //aStrConverted.Append( '.' ); 701 else if ( cChar == '.' ) // special case, if decimal seperator isn't '.' we have to put the string after it 702 continue; // #99189# OJ 703 else if (cThousandDelimiter && cChar == cThousandDelimiter) 704 { 705 // weglassen 706 } 707 else 708 *pData++ = cChar; 709 //aStrConverted.Append(cChar); 710 } // for (xub_StrLen j = 0; j < aStr.Len(); ++j) 711 aStrConverted.ReleaseBufferAccess(xub_StrLen(pData - pStart)); 712 } // if ( DataType::INTEGER != nType ) 713 else 714 { 715 aStrConverted = aStr; 716 if ( cThousandDelimiter ) 717 aStrConverted.EraseAllChars(cThousandDelimiter); 718 } 719 const double nVal = ::rtl::math::stringToDouble(aStrConverted,'.',',',NULL,NULL); 720 721 // #99178# OJ 722 if ( DataType::DECIMAL == nType || DataType::NUMERIC == nType ) 723 *(_rRow->get())[i] = ::rtl::OUString::valueOf(nVal); 724 else 725 *(_rRow->get())[i] = nVal; 726 } break; 727 728 default: 729 { 730 // Wert als String in Variable der Row uebernehmen 731 *(_rRow->get())[i] = ORowSetValue(aStr); 732 } 733 break; 734 } // switch(nType) 735 (_rRow->get())[i]->setTypeKind(nType); 736 } 737 } 738 return sal_True; 739 } 740 void OFlatTable::refreshHeader() 741 { 742 m_nRowPos = 0; 743 } 744 // ----------------------------------------------------------------------------- 745 sal_Bool OFlatTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) 746 { 747 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::seekRow" ); 748 OSL_ENSURE(m_pFileStream,"OFlatTable::seekRow: FileStream is NULL!"); 749 // ---------------------------------------------------------- 750 // Positionierung vorbereiten: 751 m_nFilePos = nCurPos; 752 753 switch(eCursorPosition) 754 { 755 case IResultSetHelper::FIRST: 756 m_nRowPos = 0; 757 // run through 758 case IResultSetHelper::NEXT: 759 { 760 ++m_nRowPos; 761 ::std::map<sal_Int32,TRowPositionsInFile::iterator>::const_iterator aFind = m_aRowPosToFilePos.find(m_nRowPos); 762 m_bNeedToReadLine = aFind != m_aRowPosToFilePos.end(); 763 if ( m_bNeedToReadLine ) 764 { 765 m_nFilePos = aFind->second->first; 766 nCurPos = aFind->second->second; 767 } // if ( m_bNeedToReadLine ) 768 else 769 { 770 if ( m_nRowPos == 1 ) 771 m_nFilePos = m_nStartRowFilePos; 772 m_pFileStream->Seek(m_nFilePos); 773 if ( m_pFileStream->IsEof() || !readLine(nCurPos) /*|| !checkHeaderLine()*/) 774 { 775 m_nMaxRowCount = m_nRowPos -1; 776 return sal_False; 777 } // if ( m_pFileStream->IsEof() || !readLine(nCurPos) /*|| !checkHeaderLine()*/) 778 779 TRowPositionsInFile::iterator aPos = m_aFilePosToEndLinePos.insert(TRowPositionsInFile::value_type(m_nFilePos,nCurPos)).first; 780 m_aRowPosToFilePos.insert(::std::map<sal_Int32,TRowPositionsInFile::iterator>::value_type(m_nRowPos,aPos)); 781 } 782 } 783 784 break; 785 case IResultSetHelper::PRIOR: 786 --m_nRowPos; 787 if(m_nRowPos > 0) 788 { 789 TRowPositionsInFile::iterator aPositions = m_aRowPosToFilePos[m_nRowPos]; 790 m_nFilePos = aPositions->first; 791 nCurPos = aPositions->second; 792 m_bNeedToReadLine = true; 793 } 794 else 795 m_nRowPos = 0; 796 797 break; 798 case IResultSetHelper::LAST: 799 if ( m_nMaxRowCount ) 800 { 801 ::std::map<sal_Int32,TRowPositionsInFile::iterator>::reverse_iterator aLastPos = m_aRowPosToFilePos.rbegin(); 802 m_nRowPos = aLastPos->first; 803 m_nFilePos = aLastPos->second->first; 804 nCurPos = aLastPos->second->second; 805 806 //m_pFileStream->Seek(m_nFilePos); 807 m_bNeedToReadLine = true; 808 //if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) ) 809 // return sal_False; 810 } 811 else 812 { 813 while(seekRow(IResultSetHelper::NEXT,1,nCurPos)) ; // run through after last row 814 // now I know all 815 seekRow(IResultSetHelper::PRIOR,1,nCurPos); 816 } 817 break; 818 case IResultSetHelper::RELATIVE: 819 if(nOffset > 0) 820 { 821 for(sal_Int32 i = 0;i<nOffset;++i) 822 seekRow(IResultSetHelper::NEXT,1,nCurPos); 823 } 824 else if(nOffset < 0) 825 { 826 for(sal_Int32 i = nOffset;i;++i) 827 seekRow(IResultSetHelper::PRIOR,1,nCurPos); 828 } 829 break; 830 case IResultSetHelper::ABSOLUTE: 831 { 832 if(nOffset < 0) 833 nOffset = m_nRowPos + nOffset; 834 ::std::map<sal_Int32,TRowPositionsInFile::iterator>::const_iterator aIter = m_aRowPosToFilePos.find(nOffset); 835 if(aIter != m_aRowPosToFilePos.end()) 836 { 837 m_nFilePos = aIter->second->first; 838 nCurPos = aIter->second->second; 839 //m_pFileStream->Seek(m_nFilePos); 840 m_bNeedToReadLine = true; 841 //if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) ) 842 // return sal_False; 843 } 844 else if(m_nMaxRowCount && nOffset > m_nMaxRowCount) // offset is outside the table 845 { 846 m_nRowPos = m_nMaxRowCount; 847 return sal_False; 848 } 849 else 850 { 851 aIter = m_aRowPosToFilePos.upper_bound(nOffset); 852 if(aIter == m_aRowPosToFilePos.end()) 853 { 854 ::std::map<sal_Int32,TRowPositionsInFile::iterator>::reverse_iterator aLastPos = m_aRowPosToFilePos.rbegin(); 855 m_nRowPos = aLastPos->first; 856 nCurPos = m_nFilePos = aLastPos->second->first; 857 while(m_nRowPos != nOffset) 858 seekRow(IResultSetHelper::NEXT,1,nCurPos); 859 } 860 else 861 { 862 --aIter; 863 m_nRowPos = aIter->first; 864 m_nFilePos = aIter->second->first; 865 nCurPos = aIter->second->second; 866 //m_pFileStream->Seek(m_nFilePos); 867 m_bNeedToReadLine = true; 868 //if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) ) 869 // return sal_False; 870 } 871 } 872 } 873 874 break; 875 case IResultSetHelper::BOOKMARK: 876 { 877 TRowPositionsInFile::const_iterator aFind = m_aFilePosToEndLinePos.find(nOffset); 878 m_bNeedToReadLine = aFind != m_aFilePosToEndLinePos.end(); 879 if ( m_bNeedToReadLine ) 880 { 881 m_nFilePos = aFind->first; 882 nCurPos = aFind->second; 883 } 884 else 885 { 886 m_nFilePos = nOffset; 887 m_pFileStream->Seek(nOffset); 888 if (m_pFileStream->IsEof() || !readLine(nCurPos) ) 889 return sal_False; 890 } 891 break; 892 } 893 } 894 895 //nCurPos = m_nFilePos; 896 897 return sal_True; 898 } 899 // ----------------------------------------------------------------------------- 900 sal_Bool OFlatTable::readLine(sal_Int32& _rnCurrentPos) 901 { 902 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::readLine" ); 903 const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding(); 904 m_pFileStream->ReadByteStringLine(m_aCurrentLine,nEncoding); 905 if (m_pFileStream->IsEof()) 906 return sal_False; 907 908 QuotedTokenizedString sLine = m_aCurrentLine; // check if the string continues on next line 909 while( (sLine.GetString().GetTokenCount(m_cStringDelimiter) % 2) != 1 ) 910 { 911 m_pFileStream->ReadByteStringLine(sLine,nEncoding); 912 if ( !m_pFileStream->IsEof() ) 913 { 914 m_aCurrentLine.GetString().Append('\n'); 915 m_aCurrentLine.GetString() += sLine.GetString(); 916 sLine = m_aCurrentLine; 917 } 918 else 919 break; 920 } 921 _rnCurrentPos = m_pFileStream->Tell(); 922 return sal_True; 923 } 924 925