update emoji autocorrect entries from po-files
[LibreOffice.git] / connectivity / source / drivers / flat / ETable.cxx
blob854ea23717735e336a9c0a7d24d50d1669112bfb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <ctype.h>
21 #include "flat/ETable.hxx"
22 #include <com/sun/star/sdbc/ColumnValue.hpp>
23 #include <com/sun/star/sdbc/DataType.hpp>
24 #include <com/sun/star/ucb/XContentAccess.hpp>
25 #include <svl/converter.hxx>
26 #include "flat/EConnection.hxx"
27 #include "flat/EColumns.hxx"
28 #include <osl/thread.h>
29 #include <svl/zforlist.hxx>
30 #include <rtl/math.hxx>
31 #include <cppuhelper/queryinterface.hxx>
32 #include <comphelper/extract.hxx>
33 #include <comphelper/numbers.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/sequence.hxx>
36 #include <comphelper/string.hxx>
37 #include <comphelper/types.hxx>
38 #include "flat/EDriver.hxx"
39 #include <com/sun/star/util/NumberFormat.hpp>
40 #include <com/sun/star/util/NumberFormatter.hpp>
41 #include <com/sun/star/util/NumberFormatsSupplier.hpp>
42 #include <unotools/configmgr.hxx>
43 #include <i18nlangtag/languagetag.hxx>
44 #include <connectivity/dbconversion.hxx>
45 #include "file/quotedstring.hxx"
46 #include <unotools/syslocale.hxx>
48 using namespace ::comphelper;
49 using namespace connectivity;
50 using namespace connectivity::flat;
51 using namespace connectivity::file;
52 using namespace ::cppu;
53 using namespace utl;
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::ucb;
56 using namespace ::com::sun::star::beans;
57 using namespace ::com::sun::star::sdbcx;
58 using namespace ::com::sun::star::sdbc;
59 using namespace ::com::sun::star::container;
60 using namespace ::com::sun::star::lang;
61 using namespace ::com::sun::star::util;
62 using std::vector;
63 using std::lower_bound;
66 void OFlatTable::fillColumns(const ::com::sun::star::lang::Locale& _aLocale)
68 m_bNeedToReadLine = true; // we overwrite m_aCurrentLine, seek the stream, ...
69 m_pFileStream->Seek(0);
70 m_aCurrentLine = QuotedTokenizedString();
71 bool bRead = true;
73 const OFlatConnection* const pConnection = getFlatConnection();
74 const bool bHasHeaderLine = pConnection->isHeaderLine();
76 QuotedTokenizedString aHeaderLine;
77 TRowPositionInFile rowPos(0, 0);
78 sal_Int32 rowNum(0);
79 if ( bHasHeaderLine )
81 bRead = readLine(&rowPos.second, &rowPos.first, true);
82 if(bRead)
83 aHeaderLine = m_aCurrentLine;
85 setRowPos(rowNum++, rowPos);
87 // read first row
88 QuotedTokenizedString aFirstLine;
89 if(bRead)
91 bRead = readLine(&rowPos.second, &rowPos.first, false);
92 if(bRead)
93 setRowPos(rowNum++, rowPos);
96 if ( !bHasHeaderLine || !aHeaderLine.Len())
98 // use first non-empty row as headerline because we need the number of columns
99 while(bRead && m_aCurrentLine.Len() == 0)
101 bRead = readLine(&rowPos.second, &rowPos.first, false);
102 if(bRead)
103 setRowPos(rowNum++, rowPos);
105 aHeaderLine = m_aCurrentLine;
107 // column count
108 const sal_Int32 nFieldCount = aHeaderLine.GetTokenCount(m_cFieldDelimiter,m_cStringDelimiter);
110 if(!m_aColumns.is())
111 m_aColumns = new OSQLColumns();
112 else
113 m_aColumns->get().clear();
115 m_aTypes.clear();
116 m_aPrecisions.clear();
117 m_aScales.clear();
118 // reserve some space
119 m_aColumns->get().reserve(nFieldCount+1);
120 m_aTypes.assign(nFieldCount+1,DataType::SQLNULL);
121 m_aPrecisions.assign(nFieldCount+1,-1);
122 m_aScales.assign(nFieldCount+1,-1);
124 const bool bCase = m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers();
125 CharClass aCharClass( pConnection->getDriver()->getComponentContext(), LanguageTag( _aLocale));
126 // read description
127 const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter();
128 const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter();
129 ::comphelper::UStringMixEqual aCase(bCase);
130 vector<OUString> aColumnNames;
131 vector<OUString> m_aTypeNames;
132 m_aTypeNames.resize(nFieldCount);
133 const sal_Int32 nMaxRowsToScan = pConnection->getMaxRowsToScan();
134 sal_Int32 nRowCount = 0;
138 sal_Int32 nStartPosHeaderLine = 0; // use for efficient way to get the tokens
139 sal_Int32 nStartPosFirstLine = 0; // use for efficient way to get the tokens
140 sal_Int32 nStartPosFirstLine2 = 0;
141 for( sal_Int32 i = 0; i < nFieldCount; i++ )
143 if ( nRowCount == 0)
145 OUString aColumnName;
146 if ( bHasHeaderLine )
148 aColumnName = aHeaderLine.GetTokenSpecial(nStartPosHeaderLine,m_cFieldDelimiter,m_cStringDelimiter);
150 if ( aColumnName.isEmpty() )
152 aColumnName = "C" + OUString::number(i+1);
154 aColumnNames.push_back(aColumnName);
156 if(bRead)
158 impl_fillColumnInfo_nothrow(m_aCurrentLine, nStartPosFirstLine, nStartPosFirstLine2,
159 m_aTypes[i], m_aPrecisions[i], m_aScales[i], m_aTypeNames[i],
160 cDecimalDelimiter, cThousandDelimiter, aCharClass);
163 ++nRowCount;
164 bRead = readLine(&rowPos.second, &rowPos.first, false);
165 if(bRead)
166 setRowPos(rowNum++, rowPos);
168 while(nRowCount < nMaxRowsToScan && bRead);
170 for( sal_Int32 i = 0; i < nFieldCount; i++ )
172 // check if the columname already exists
173 OUString aAlias(aColumnNames[i]);
174 OSQLColumns::Vector::const_iterator aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase);
175 sal_Int32 nExprCnt = 0;
176 while(aFind != m_aColumns->get().end())
178 aAlias = aColumnNames[i] + OUString::number(++nExprCnt);
179 aFind = connectivity::find(m_aColumns->get().begin(),m_aColumns->get().end(),aAlias,aCase);
182 sdbcx::OColumn* pColumn = new sdbcx::OColumn(aAlias,m_aTypeNames[i],OUString(),OUString(),
183 ColumnValue::NULLABLE,
184 m_aPrecisions[i],
185 m_aScales[i],
186 m_aTypes[i],
187 false,
188 false,
189 false,
190 bCase,
191 m_CatalogName, getSchema(), getName());
192 Reference< XPropertySet> xCol = pColumn;
193 m_aColumns->get().push_back(xCol);
196 m_pFileStream->Seek(m_aRowPosToFilePos[0].second);
199 void OFlatTable::impl_fillColumnInfo_nothrow(QuotedTokenizedString& aFirstLine, sal_Int32& nStartPosFirstLine, sal_Int32& nStartPosFirstLine2,
200 sal_Int32& io_nType, sal_Int32& io_nPrecisions, sal_Int32& io_nScales, OUString& o_sTypeName,
201 const sal_Unicode cDecimalDelimiter, const sal_Unicode cThousandDelimiter, const CharClass& aCharClass)
203 if ( io_nType != DataType::VARCHAR )
205 bool bNumeric = io_nType == DataType::SQLNULL || io_nType == DataType::DOUBLE || io_nType == DataType::DECIMAL || io_nType == DataType::INTEGER;
206 sal_uLong nIndex = 0;
208 if ( bNumeric )
210 // first without fielddelimiter
211 OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter,'\0');
212 if (aField.isEmpty() ||
213 (m_cStringDelimiter && m_cStringDelimiter == aField[0]))
215 bNumeric = false;
216 if ( m_cStringDelimiter != '\0' )
217 aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
218 else
219 nStartPosFirstLine2 = nStartPosFirstLine;
221 else
223 OUString aField2;
224 if ( m_cStringDelimiter != '\0' )
225 aField2 = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
226 else
227 aField2 = aField;
229 if (aField2.isEmpty())
231 bNumeric = false;
233 else
235 bNumeric = true;
236 sal_Int32 nDot = 0;
237 sal_Int32 nDecimalDelCount = 0;
238 sal_Int32 nSpaceCount = 0;
239 for( sal_Int32 j = 0; j < aField2.getLength(); j++ )
241 const sal_Unicode c = aField2[j];
242 if ( j == nSpaceCount && m_cFieldDelimiter != 32 && c == 32 )
244 ++nSpaceCount;
245 continue;
247 // just digits, decimal- and thousands-delimiter?
248 if ( ( !cDecimalDelimiter || c != cDecimalDelimiter ) &&
249 ( !cThousandDelimiter || c != cThousandDelimiter ) &&
250 !aCharClass.isDigit(aField2,j) &&
251 ( j != 0 || (c != '+' && c != '-' ) ) )
253 bNumeric = false;
254 break;
256 if (cDecimalDelimiter && c == cDecimalDelimiter)
258 io_nPrecisions = 15; // we have an decimal value
259 io_nScales = 2;
260 ++nDecimalDelCount;
261 } // if (cDecimalDelimiter && c == cDecimalDelimiter)
262 if ( c == '.' )
263 ++nDot;
266 if (nDecimalDelCount > 1 || nDot > 1 ) // if there is more than one dot it isn't a number
267 bNumeric = false;
268 if (bNumeric && cThousandDelimiter)
270 // Is the delimiter correct?
271 const OUString aValue = aField2.getToken(0,cDecimalDelimiter);
272 for( sal_Int32 j = aValue.getLength() - 4; j >= 0; j -= 4)
274 const sal_Unicode c = aValue[j];
275 // just digits, decimal- and thousands-delimiter?
276 if (c == cThousandDelimiter && j)
277 continue;
278 else
280 bNumeric = false;
281 break;
286 // now also check for a date field
287 if (!bNumeric)
291 nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2);
293 catch(Exception&)
300 else if ( io_nType == DataType::DATE || io_nType == DataType::TIMESTAMP || io_nType == DataType::TIME)
302 OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter,'\0');
303 if (aField.isEmpty() ||
304 (m_cStringDelimiter && m_cStringDelimiter == aField[0]))
307 else
309 OUString aField2;
310 if ( m_cStringDelimiter != '\0' )
311 aField2 = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
312 else
313 aField2 = aField;
314 if (!aField2.isEmpty() )
318 nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2);
320 catch(Exception&)
327 sal_Int32 nFlags = 0;
328 if (bNumeric)
330 if (cDecimalDelimiter)
332 if(io_nPrecisions)
334 io_nType = DataType::DECIMAL;
335 o_sTypeName = "DECIMAL";
337 else
339 io_nType = DataType::DOUBLE;
340 o_sTypeName = "DOUBLE";
343 else
345 io_nType = DataType::INTEGER;
346 io_nPrecisions = 0;
347 io_nScales = 0;
349 nFlags = ColumnSearch::BASIC;
351 else
353 switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex))
355 case css::util::NumberFormat::DATE:
356 io_nType = DataType::DATE;
357 o_sTypeName = "DATE";
358 break;
359 case css::util::NumberFormat::DATETIME:
360 io_nType = DataType::TIMESTAMP;
361 o_sTypeName = "TIMESTAMP";
362 break;
363 case css::util::NumberFormat::TIME:
364 io_nType = DataType::TIME;
365 o_sTypeName = "TIME";
366 break;
367 default:
368 io_nType = DataType::VARCHAR;
369 io_nPrecisions = 0; // nyi: Data can be longer!
370 io_nScales = 0;
371 o_sTypeName = "VARCHAR";
373 nFlags |= ColumnSearch::CHAR;
376 else
378 OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter,'\0');
379 if (aField.isEmpty() ||
380 (m_cStringDelimiter && m_cStringDelimiter == aField[0]))
382 if ( m_cStringDelimiter != '\0' )
383 aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine2, m_cFieldDelimiter, m_cStringDelimiter);
384 else
385 nStartPosFirstLine2 = nStartPosFirstLine;
387 else
389 if ( m_cStringDelimiter != '\0' )
390 aFirstLine.GetTokenSpecial(nStartPosFirstLine2, m_cFieldDelimiter, m_cStringDelimiter);
395 OFlatTable::OFlatTable(sdbcx::OCollection* _pTables,OFlatConnection* _pConnection,
396 const OUString& _Name,
397 const OUString& _Type,
398 const OUString& _Description ,
399 const OUString& _SchemaName,
400 const OUString& _CatalogName
401 ) : OFlatTable_BASE(_pTables,_pConnection,_Name,
402 _Type,
403 _Description,
404 _SchemaName,
405 _CatalogName)
406 ,m_nRowPos(0)
407 ,m_nMaxRowCount(0)
408 ,m_cStringDelimiter(_pConnection->getStringDelimiter())
409 ,m_cFieldDelimiter(_pConnection->getFieldDelimiter())
410 ,m_bNeedToReadLine(false)
415 void OFlatTable::construct()
417 SvtSysLocale aLocale;
418 ::com::sun::star::lang::Locale aAppLocale(aLocale.GetLanguageTag().getLocale());
420 Reference< XNumberFormatsSupplier > xSupplier = NumberFormatsSupplier::createWithLocale( m_pConnection->getDriver()->getComponentContext(), aAppLocale );
421 m_xNumberFormatter.set( NumberFormatter::create( m_pConnection->getDriver()->getComponentContext()), UNO_QUERY_THROW);
422 m_xNumberFormatter->attachNumberFormatsSupplier(xSupplier);
423 Reference<XPropertySet> xProp(xSupplier->getNumberFormatSettings(),UNO_QUERY);
424 xProp->getPropertyValue("NullDate") >>= m_aNullDate;
426 INetURLObject aURL;
427 aURL.SetURL(getEntry());
429 if(aURL.getExtension() != OUString(m_pConnection->getExtension()))
430 aURL.setExtension(m_pConnection->getExtension());
432 OUString aFileName = aURL.GetMainURL(INetURLObject::NO_DECODE);
434 m_pFileStream = createStream_simpleError( aFileName, STREAM_READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE);
436 if(!m_pFileStream)
437 m_pFileStream = createStream_simpleError( aFileName, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE);
439 if(m_pFileStream)
441 sal_uInt64 const nSize = m_pFileStream->remainingSize();
443 // Buffersize is dependent on the file-size
444 m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 :
445 nSize > 100000 ? 16384 :
446 nSize > 10000 ? 4096 : 1024);
448 fillColumns(aAppLocale);
450 refreshColumns();
454 OUString OFlatTable::getEntry()
456 OUString sURL;
459 Reference< XResultSet > xDir = m_pConnection->getDir()->getStaticResultSet();
460 Reference< XRow> xRow(xDir,UNO_QUERY);
461 OUString sName;
462 OUString sExt;
464 INetURLObject aURL;
465 xDir->beforeFirst();
466 static const char s_sSeparator[] = "/";
467 while(xDir->next())
469 sName = xRow->getString(1);
470 aURL.SetSmartProtocol(INetProtocol::File);
471 OUString sUrl = m_pConnection->getURL() + s_sSeparator + sName;
472 aURL.SetSmartURL( sUrl );
474 // cut the extension
475 sExt = aURL.getExtension();
477 // name and extension have to coincide
478 if ( m_pConnection->matchesExtension( sExt ) )
480 if ( !sExt.isEmpty() )
481 sName = sName.replaceAt(sName.getLength() - (sExt.getLength() + 1), sExt.getLength()+1, OUString());
482 if ( sName == m_Name )
484 Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY );
485 sURL = xContentAccess->queryContentIdentifierString();
486 break;
490 xDir->beforeFirst(); // move back to before first record
492 catch(const Exception&)
494 OSL_ASSERT(false);
496 return sURL;
499 void OFlatTable::refreshColumns()
501 ::osl::MutexGuard aGuard( m_aMutex );
503 TStringVector aVector;
504 aVector.reserve(m_aColumns->get().size());
506 for(OSQLColumns::Vector::const_iterator aIter = m_aColumns->get().begin();aIter != m_aColumns->get().end();++aIter)
507 aVector.push_back(Reference< XNamed>(*aIter,UNO_QUERY)->getName());
509 if(m_pColumns)
510 m_pColumns->reFill(aVector);
511 else
512 m_pColumns = new OFlatColumns(this,m_aMutex,aVector);
516 void SAL_CALL OFlatTable::disposing()
518 OFileTable::disposing();
519 ::osl::MutexGuard aGuard(m_aMutex);
520 m_aColumns = NULL;
523 Sequence< Type > SAL_CALL OFlatTable::getTypes( ) throw(RuntimeException, std::exception)
525 Sequence< Type > aTypes = OTable_TYPEDEF::getTypes();
526 vector<Type> aOwnTypes;
527 aOwnTypes.reserve(aTypes.getLength());
528 const Type* pBegin = aTypes.getConstArray();
529 const Type* pEnd = pBegin + aTypes.getLength();
530 for(;pBegin != pEnd;++pBegin)
532 if(!(*pBegin == cppu::UnoType<XKeysSupplier>::get()||
533 *pBegin == cppu::UnoType<XRename>::get()||
534 *pBegin == cppu::UnoType<XIndexesSupplier>::get()||
535 *pBegin == cppu::UnoType<XAlterTable>::get()||
536 *pBegin == cppu::UnoType<XDataDescriptorFactory>::get()))
538 aOwnTypes.push_back(*pBegin);
541 return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
545 Any SAL_CALL OFlatTable::queryInterface( const Type & rType ) throw(RuntimeException, std::exception)
547 if( rType == cppu::UnoType<XKeysSupplier>::get()||
548 rType == cppu::UnoType<XIndexesSupplier>::get()||
549 rType == cppu::UnoType<XRename>::get()||
550 rType == cppu::UnoType<XAlterTable>::get()||
551 rType == cppu::UnoType<XDataDescriptorFactory>::get())
552 return Any();
554 Any aRet = OTable_TYPEDEF::queryInterface(rType);
555 return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< ::com::sun::star::lang::XUnoTunnel*> (this));
559 Sequence< sal_Int8 > OFlatTable::getUnoTunnelImplementationId()
561 static ::cppu::OImplementationId * pId = 0;
562 if (! pId)
564 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
565 if (! pId)
567 static ::cppu::OImplementationId aId;
568 pId = &aId;
571 return pId->getImplementationId();
574 // com::sun::star::lang::XUnoTunnel
576 sal_Int64 OFlatTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException, std::exception)
578 return (rId.getLength() == 16 && 0 == memcmp(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) )
579 ? reinterpret_cast< sal_Int64 >( this )
580 : OFlatTable_BASE::getSomething(rId);
583 bool OFlatTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns & _rCols, bool bIsTable, bool bRetrieveData)
585 *(_rRow->get())[0] = m_nFilePos;
587 if (!bRetrieveData)
588 return true;
590 bool result = false;
591 if ( m_bNeedToReadLine )
593 m_pFileStream->Seek(m_nFilePos);
594 TRowPositionInFile rowPos(0, 0);
595 if(readLine(&rowPos.second, &rowPos.first))
597 setRowPos(m_nRowPos, rowPos);
598 m_bNeedToReadLine = false;
599 result = true;
601 // else let run through so that we set _rRow to all NULL
604 const OFlatConnection * const pConnection = getFlatConnection();
605 const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter();
606 const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter();
607 // Fields:
608 sal_Int32 nStartPos = 0;
609 OSQLColumns::Vector::const_iterator aIter = _rCols.get().begin();
610 OSQLColumns::Vector::const_iterator aEnd = _rCols.get().end();
611 const OValueRefVector::Vector::size_type nCount = _rRow->get().size();
612 for (OValueRefVector::Vector::size_type i = 1;
613 aIter != aEnd && i < nCount;
614 ++aIter, i++)
616 OUString aStr = m_aCurrentLine.GetTokenSpecial(nStartPos,m_cFieldDelimiter,m_cStringDelimiter);
618 if (aStr.isEmpty())
620 (_rRow->get())[i]->setNull();
622 else
624 // lengths depending on data-type:
625 sal_Int32 nLen;
626 sal_Int32 nType = 0;
627 if(bIsTable)
629 nLen = m_aPrecisions[i-1];
630 nType = m_aTypes[i-1];
632 else
634 Reference< XPropertySet> xColumn = *aIter;
635 xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nLen;
636 xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
638 switch(nType)
640 case DataType::TIMESTAMP:
641 case DataType::DATE:
642 case DataType::TIME:
646 double nRes = m_xNumberFormatter->convertStringToNumber(::com::sun::star::util::NumberFormat::ALL,aStr);
648 switch(nType)
650 case DataType::DATE:
651 *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes,m_aNullDate));
652 break;
653 case DataType::TIMESTAMP:
654 *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes,m_aNullDate));
655 break;
656 default:
657 *(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes));
660 catch(Exception&)
662 (_rRow->get())[i]->setNull();
664 } break;
665 case DataType::DOUBLE:
666 case DataType::INTEGER:
667 case DataType::DECIMAL:
668 case DataType::NUMERIC:
671 OUString aStrConverted;
672 if ( DataType::INTEGER != nType )
674 OSL_ENSURE((cDecimalDelimiter && nType != DataType::INTEGER) ||
675 (!cDecimalDelimiter && nType == DataType::INTEGER),
676 "FalscherTyp");
678 OUStringBuffer aBuf(aStr.getLength());
679 // convert to Standard-Notation (DecimalPOINT without thousands-comma):
680 for (sal_Int32 j = 0; j < aStr.getLength(); ++j)
682 const sal_Unicode cChar = aStr[j];
683 if (cDecimalDelimiter && cChar == cDecimalDelimiter)
684 aBuf.append('.');
685 else if ( cChar == '.' ) // special case, if decimal separator isn't '.' we have to put the string after it
686 continue;
687 else if (cThousandDelimiter && cChar == cThousandDelimiter)
689 // leave out
691 else
692 aBuf.append(cChar);
693 } // for (j = 0; j < aStr.getLength(); ++j)
694 aStrConverted = aBuf.makeStringAndClear();
695 } // if ( DataType::INTEGER != nType )
696 else
698 if ( cThousandDelimiter )
699 aStrConverted = comphelper::string::remove(aStr, cThousandDelimiter);
700 else
701 aStrConverted = aStr;
703 const double nVal = ::rtl::math::stringToDouble(aStrConverted,'.',',',NULL,NULL);
705 // #99178# OJ
706 if ( DataType::DECIMAL == nType || DataType::NUMERIC == nType )
707 *(_rRow->get())[i] = OUString::number(nVal);
708 else
709 *(_rRow->get())[i] = nVal;
710 } break;
712 default:
714 // Copy Value as String in Row-Variable
715 *(_rRow->get())[i] = ORowSetValue(aStr);
717 break;
718 } // switch(nType)
719 (_rRow->get())[i]->setTypeKind(nType);
722 return result;
726 void OFlatTable::refreshHeader()
728 SAL_INFO( "connectivity.drivers", "flat lionel@mamane.lu OFlatTable::refreshHeader" );
732 namespace
734 template< typename Tp, typename Te> struct RangeBefore
736 bool operator() (const Tp &p, const Te &e)
738 assert(p.first <= p.second);
739 return p.second <= e;
744 bool OFlatTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos)
746 OSL_ENSURE(m_pFileStream,"OFlatTable::seekRow: FileStream is NULL!");
749 switch(eCursorPosition)
751 case IResultSetHelper::FIRST:
752 m_nRowPos = 0;
753 // run through
754 case IResultSetHelper::NEXT:
756 assert(m_nRowPos >= 0);
757 if(m_nMaxRowCount != 0 && m_nRowPos > m_nMaxRowCount)
758 return false;
759 ++m_nRowPos;
760 if(m_aRowPosToFilePos.size() > static_cast< vector< TRowPositionInFile >::size_type >(m_nRowPos))
762 m_bNeedToReadLine = true;
763 m_nFilePos = m_aRowPosToFilePos[m_nRowPos].first;
764 nCurPos = m_aRowPosToFilePos[m_nRowPos].second;
766 else
768 assert(m_aRowPosToFilePos.size() == static_cast< vector< TRowPositionInFile >::size_type >(m_nRowPos));
769 const TRowPositionInFile &lastRowPos(m_aRowPosToFilePos.back());
770 // Our ResultSet is allowed to disagree with us only
771 // on the position of the first line
772 // (because of the special case of the header...)
773 assert(m_nRowPos == 1 || nCurPos == lastRowPos.second);
775 m_nFilePos = lastRowPos.second;
776 m_pFileStream->Seek(m_nFilePos);
778 TRowPositionInFile newRowPos;
779 if(!readLine(&newRowPos.second, &newRowPos.first, false))
781 m_nMaxRowCount = m_nRowPos - 1;
782 return false;
785 nCurPos = newRowPos.second;
786 setRowPos(m_nRowPos, newRowPos);
790 break;
791 case IResultSetHelper::PRIOR:
792 assert(m_nRowPos >= 0);
794 if(m_nRowPos == 0)
795 return false;
797 --m_nRowPos;
799 assert (m_nRowPos >= 0);
800 assert(m_aRowPosToFilePos.size() >= static_cast< vector< TRowPositionInFile >::size_type >(m_nRowPos));
801 const TRowPositionInFile &aPositions(m_aRowPosToFilePos[m_nRowPos]);
802 m_nFilePos = aPositions.first;
803 nCurPos = aPositions.second;
804 m_bNeedToReadLine = true;
807 break;
808 case IResultSetHelper::LAST:
809 if (m_nMaxRowCount == 0)
811 while(seekRow(IResultSetHelper::NEXT, 1, nCurPos)) ; // run through after last row
813 // m_nMaxRowCount can still be zero, but now it means there a genuinely zero rows in the table
814 return seekRow(IResultSetHelper::ABSOLUTE1, m_nMaxRowCount, nCurPos);
815 break;
816 case IResultSetHelper::RELATIVE1:
818 const sal_Int32 nNewRowPos = m_nRowPos + nOffset;
819 if (nNewRowPos < 0)
820 return false;
821 // ABSOLUTE will take care of case nNewRowPos > nMaxRowCount
822 return seekRow(IResultSetHelper::ABSOLUTE1, nNewRowPos, nCurPos);
824 case IResultSetHelper::ABSOLUTE1:
826 if(nOffset < 0)
828 if (m_nMaxRowCount == 0)
830 if (!seekRow(IResultSetHelper::LAST, 0, nCurPos))
831 return false;
833 // m_nMaxRowCount can still be zero, but now it means there a genuinely zero rows in the table
834 nOffset = m_nMaxRowCount + nOffset;
836 if(nOffset < 0)
838 seekRow(IResultSetHelper::ABSOLUTE1, 0, nCurPos);
839 return false;
841 if(m_nMaxRowCount && nOffset > m_nMaxRowCount)
843 m_nRowPos = m_nMaxRowCount + 1;
844 const TRowPositionInFile &lastRowPos(m_aRowPosToFilePos.back());
845 m_nFilePos = lastRowPos.second;
846 nCurPos = lastRowPos.second;
847 return false;
850 assert(m_nRowPos >=0);
851 assert(m_aRowPosToFilePos.size() > static_cast< vector< TRowPositionInFile >::size_type >(m_nRowPos));
852 assert(nOffset >= 0);
853 if(m_aRowPosToFilePos.size() > static_cast< vector< TRowPositionInFile >::size_type >(nOffset))
855 m_nFilePos = m_aRowPosToFilePos[nOffset].first;
856 nCurPos = m_aRowPosToFilePos[nOffset].second;
857 m_nRowPos = nOffset;
858 m_bNeedToReadLine = true;
860 else
862 assert(m_nRowPos < nOffset);
863 while(m_nRowPos < nOffset)
865 if(!seekRow(IResultSetHelper::NEXT, 1, nCurPos))
866 return false;
868 assert(m_nRowPos == nOffset);
872 break;
873 case IResultSetHelper::BOOKMARK:
875 vector< TRowPositionInFile >::const_iterator aFind = lower_bound(m_aRowPosToFilePos.begin(),
876 m_aRowPosToFilePos.end(),
877 nOffset,
878 RangeBefore< TRowPositionInFile, sal_Int32 >());
880 if(aFind == m_aRowPosToFilePos.end() || aFind->first != nOffset)
881 //invalid bookmark
882 return false;
884 m_bNeedToReadLine = true;
885 m_nFilePos = aFind->first;
886 nCurPos = aFind->second;
887 m_nRowPos = aFind - m_aRowPosToFilePos.begin();
888 break;
892 return true;
896 bool OFlatTable::readLine(sal_Int32 * const pEndPos, sal_Int32 * const pStartPos, const bool nonEmpty)
898 const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding();
899 m_aCurrentLine = QuotedTokenizedString();
902 if (pStartPos)
903 *pStartPos = (sal_Int32)m_pFileStream->Tell();
904 m_pFileStream->ReadByteStringLine(m_aCurrentLine, nEncoding);
905 if (m_pFileStream->IsEof())
906 return false;
908 QuotedTokenizedString sLine = m_aCurrentLine; // check if the string continues on next line
909 while( (comphelper::string::getTokenCount(sLine.GetString(), m_cStringDelimiter) % 2) != 1 )
911 m_pFileStream->ReadByteStringLine(sLine,nEncoding);
912 if ( !m_pFileStream->IsEof() )
914 OUString aStr = m_aCurrentLine.GetString() + "\n" + sLine.GetString();
915 m_aCurrentLine.SetString(aStr);
916 sLine = m_aCurrentLine;
918 else
919 break;
922 while(nonEmpty && m_aCurrentLine.Len() == 0);
924 if(pEndPos)
925 *pEndPos = (sal_Int32)m_pFileStream->Tell();
926 return true;
930 void OFlatTable::setRowPos(const vector<TRowPositionInFile>::size_type rowNum, const TRowPositionInFile &rowPos)
932 assert(m_aRowPosToFilePos.size() >= rowNum);
933 if(m_aRowPosToFilePos.size() == rowNum)
934 m_aRowPosToFilePos.push_back(rowPos);
935 else
937 SAL_WARN_IF(m_aRowPosToFilePos[rowNum] != rowPos,
938 "connectivity.flat",
939 "Setting position for row " << rowNum << " to (" << rowPos.first << ", " << rowPos.second << "), "
940 "but already had different position (" << m_aRowPosToFilePos[rowNum].first << ", " << m_aRowPosToFilePos[rowNum].second << ")");
941 m_aRowPosToFilePos[rowNum] = rowPos;
945 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */