xref: /AOO41X/main/connectivity/source/drivers/flat/ETable.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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