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