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 // -------------------------------------------------------------------------
fillColumns(const::com::sun::star::lang::Locale & _aLocale)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 sal_Int32 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 	::rtl::OUString 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 	    sal_Int32 nStartPosHeaderLine = 0; // use for eficient way to get the tokens
131 	    sal_Int32 nStartPosFirstLine = 0; // use for eficient way to get the tokens
132 	    sal_Int32 nStartPosFirstLine2 = 0;
133 	    for (sal_Int32 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.isEmpty() )
141 			        {
142 				        aColumnName = ::rtl::OUString::createFromAscii( "C" );
143 				        aColumnName += String::CreateFromInt32(i+1);
144 			        }
145 		        }
146 		        else
147 		        {
148 			        // no column name so ...
149 			        aColumnName = ::rtl::OUString::createFromAscii( "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 (sal_Int32 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 }
impl_fillColumnInfo_nothrow(QuotedTokenizedString & aFirstLine,sal_Int32 & nStartPosFirstLine,sal_Int32 & nStartPosFirstLine2,sal_Int32 & io_nType,sal_Int32 & io_nPrecisions,sal_Int32 & io_nScales,String & o_sTypeName,const sal_Unicode cDecimalDelimiter,const sal_Unicode cThousandDelimiter,const CharClass & aCharClass)186 void OFlatTable::impl_fillColumnInfo_nothrow(QuotedTokenizedString& aFirstLine,sal_Int32& nStartPosFirstLine,sal_Int32& 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 	        ::rtl::OUString aField;
199 	        aFirstLine.GetTokenSpecial(&aField,nStartPosFirstLine,m_cFieldDelimiter,'\0');
200 	        if ( aField.isEmpty() ||
201 		        (m_cStringDelimiter && m_cStringDelimiter == aField[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 		        ::rtl::OUString aField2;
212 		        if ( m_cStringDelimiter != '\0' )
213 			        aFirstLine.GetTokenSpecial(&aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
214 		        else
215 			        aField2 = aField;
216 
217 		        if ( aField2.isEmpty() )
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 (sal_Int32 j = 0; j < aField2.getLength(); j++)
228 			        {
229 				        const sal_Unicode c = aField2[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                         sal_Int32 tokenIdx = 0;
260 				        const ::rtl::OUString aValue = aField2.getToken(0,cDecimalDelimiter,tokenIdx);
261 				        for (sal_Int32 j = aValue.getLength() - 4; j >= 0; j -= 4)
262 				        {
263 					        const sal_Unicode c = aValue[j];
264 					        // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen?
265 					        if (c == cThousandDelimiter && j)
266 						        continue;
267 					        else
268 					        {
269 						        bNumeric = sal_False;
270 						        break;
271 					        }
272 				        }
273 			        }
274 
275                     // jetzt koennte es noch ein Datumsfeld sein
276 			        if (!bNumeric)
277 			        {
278 				        try
279 				        {
280 					        nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2);
281 				        }
282 				        catch(Exception&)
283 				        {
284 				        }
285 			        }
286 		        }
287 	        }
288         }
289         else if ( io_nType == DataType::DATE || io_nType == DataType::TIMESTAMP || io_nType == DataType::TIME)
290         {
291             ::rtl::OUString aField;
292 	        aFirstLine.GetTokenSpecial(&aField,nStartPosFirstLine,m_cFieldDelimiter,'\0');
293             if ( aField.isEmpty() ||
294 		        (m_cStringDelimiter && m_cStringDelimiter == aField[0]))
295 	        {
296             }
297             else
298             {
299                 ::rtl::OUString aField2;
300 	            if ( m_cStringDelimiter != '\0' )
301 		            aFirstLine.GetTokenSpecial(&aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
302 	            else
303 		            aField2 = aField;
304                 if ( !aField2.isEmpty() )
305                 {
306                     try
307 	                {
308 		                nIndex = m_xNumberFormatter->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL,aField2);
309 	                }
310 	                catch(Exception&)
311 	                {
312 	                }
313                 }
314             }
315         }
316 
317 	    sal_Int32 nFlags = 0;
318 	    if (bNumeric)
319 	    {
320 		    if (cDecimalDelimiter)
321 		    {
322 			    if(io_nPrecisions)
323 			    {
324 				    io_nType = DataType::DECIMAL;
325                     static const ::rtl::OUString s_sDECIMAL(RTL_CONSTASCII_USTRINGPARAM("DECIMAL"));
326 				    o_sTypeName = s_sDECIMAL;
327 			    }
328 			    else
329 			    {
330 				    io_nType = DataType::DOUBLE;
331                     static const ::rtl::OUString s_sDOUBLE(RTL_CONSTASCII_USTRINGPARAM("DOUBLE"));
332 				    o_sTypeName = s_sDOUBLE;
333 			    }
334 		    }
335 		    else
336             {
337 			    io_nType = DataType::INTEGER;
338                 io_nPrecisions = 0;
339                 io_nScales = 0;
340             }
341 		    nFlags = ColumnSearch::BASIC;
342 	    }
343 	    else
344 	    {
345 		    switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex))
346 		    {
347 			    case NUMBERFORMAT_DATE:
348 				    io_nType = DataType::DATE;
349                     {
350                         static const ::rtl::OUString s_sDATE(RTL_CONSTASCII_USTRINGPARAM("DATE"));
351 				        o_sTypeName = s_sDATE;
352                     }
353 				    break;
354 			    case NUMBERFORMAT_DATETIME:
355 				    io_nType = DataType::TIMESTAMP;
356                     {
357                         static const ::rtl::OUString s_sTIMESTAMP(RTL_CONSTASCII_USTRINGPARAM("TIMESTAMP"));
358 				        o_sTypeName = s_sTIMESTAMP;
359                     }
360 				    break;
361 			    case NUMBERFORMAT_TIME:
362 				    io_nType = DataType::TIME;
363                     {
364                         static const ::rtl::OUString s_sTIME(RTL_CONSTASCII_USTRINGPARAM("TIME"));
365 				        o_sTypeName = s_sTIME;
366                     }
367 				    break;
368 			    default:
369 				    io_nType = DataType::VARCHAR;
370 				    io_nPrecisions = 0;	// nyi: Daten koennen aber laenger sein!
371 				    io_nScales = 0;
372                     {
373                         static const ::rtl::OUString s_sVARCHAR(RTL_CONSTASCII_USTRINGPARAM("VARCHAR"));
374 				        o_sTypeName = s_sVARCHAR;
375                     }
376 		    };
377 		    nFlags |= ColumnSearch::CHAR;
378 	    }
379     }
380     else
381     {
382         ::rtl::OUString aField;
383         aFirstLine.GetTokenSpecial(&aField,nStartPosFirstLine,m_cFieldDelimiter,'\0');
384         if ( aField.isEmpty() ||
385 		        (m_cStringDelimiter && m_cStringDelimiter == aField[0]))
386         {
387             if ( m_cStringDelimiter != '\0' )
388 		        aFirstLine.GetTokenSpecial(&aField,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
389             else
390 	            nStartPosFirstLine2 = nStartPosFirstLine;
391         }
392         else
393         {
394 	        ::rtl::OUString aField2;
395 	        if ( m_cStringDelimiter != '\0' )
396 		        aFirstLine.GetTokenSpecial(&aField2,nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter);
397         }
398     }
399 }
400 // -------------------------------------------------------------------------
OFlatTable(sdbcx::OCollection * _pTables,OFlatConnection * _pConnection,const::rtl::OUString & _Name,const::rtl::OUString & _Type,const::rtl::OUString & _Description,const::rtl::OUString & _SchemaName,const::rtl::OUString & _CatalogName)401 OFlatTable::OFlatTable(sdbcx::OCollection* _pTables,OFlatConnection* _pConnection,
402 					const ::rtl::OUString& _Name,
403 					const ::rtl::OUString& _Type,
404 					const ::rtl::OUString& _Description ,
405 					const ::rtl::OUString& _SchemaName,
406 					const ::rtl::OUString& _CatalogName
407 				) : OFlatTable_BASE(_pTables,_pConnection,_Name,
408 								  _Type,
409 								  _Description,
410 								  _SchemaName,
411 								  _CatalogName)
412 	,m_nStartRowFilePos(0)
413     ,m_nRowPos(0)
414 	,m_nMaxRowCount(0)
415     ,m_cStringDelimiter(_pConnection->getStringDelimiter())
416     ,m_cFieldDelimiter(_pConnection->getFieldDelimiter())
417     ,m_bNeedToReadLine(false)
418 {
419     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::OFlatTable" );
420 
421 }
422 // -----------------------------------------------------------------------------
construct()423 void OFlatTable::construct()
424 {
425     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::construct" );
426     SvtSysLocale aLocale;
427 	::com::sun::star::lang::Locale aAppLocale(aLocale.GetLocaleDataPtr()->getLocale());
428 	Sequence< ::com::sun::star::uno::Any > aArg(1);
429 	aArg[0] <<= aAppLocale;
430 
431 	Reference< ::com::sun::star::util::XNumberFormatsSupplier >  xSupplier(m_pConnection->getDriver()->getFactory()->createInstanceWithArguments(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatsSupplier"),aArg),UNO_QUERY);
432 	m_xNumberFormatter = Reference< ::com::sun::star::util::XNumberFormatter >(m_pConnection->getDriver()->getFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatter")),UNO_QUERY);
433 	m_xNumberFormatter->attachNumberFormatsSupplier(xSupplier);
434     Reference<XPropertySet> xProp(xSupplier->getNumberFormatSettings(),UNO_QUERY);
435 	xProp->getPropertyValue(::rtl::OUString::createFromAscii("NullDate")) >>= m_aNullDate;
436 
437 	INetURLObject aURL;
438 	aURL.SetURL(getEntry());
439 
440 	if(aURL.getExtension() != rtl::OUString(m_pConnection->getExtension()))
441 		aURL.setExtension(m_pConnection->getExtension());
442 
443 	String aFileName = aURL.GetMainURL(INetURLObject::NO_DECODE);
444 
445 	m_pFileStream = createStream_simpleError( aFileName,STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYWRITE);
446 
447 	if(!m_pFileStream)
448 		m_pFileStream = createStream_simpleError( aFileName,STREAM_READ | STREAM_NOCREATE | STREAM_SHARE_DENYNONE);
449 
450 	if(m_pFileStream)
451 	{
452 		m_pFileStream->Seek(STREAM_SEEK_TO_END);
453 		sal_Int32 nSize = m_pFileStream->Tell();
454 		m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
455 
456 		// Buffersize abhaengig von der Filegroesse
457 		m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 :
458 									nSize > 100000	? 16384 :
459 									nSize > 10000	? 4096	: 1024);
460 
461 		fillColumns(aAppLocale);
462 
463 		refreshColumns();
464 	}
465 }
466 // -------------------------------------------------------------------------
getEntry()467 String OFlatTable::getEntry()
468 {
469     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::getEntry" );
470 	::rtl::OUString sURL;
471 	try
472 	{
473 		Reference< XResultSet > xDir = m_pConnection->getDir()->getStaticResultSet();
474 		Reference< XRow> xRow(xDir,UNO_QUERY);
475 		::rtl::OUString sName;
476 		::rtl::OUString sExt;
477 
478 		INetURLObject aURL;
479 		xDir->beforeFirst();
480 		static const ::rtl::OUString s_sSeparator(RTL_CONSTASCII_USTRINGPARAM("/"));
481 		while(xDir->next())
482 		{
483 			sName = xRow->getString(1);
484 			aURL.SetSmartProtocol(INET_PROT_FILE);
485 			String sUrl = m_pConnection->getURL() +  s_sSeparator + sName;
486 			aURL.SetSmartURL( sUrl );
487 
488 			// cut the extension
489 			sExt = aURL.getExtension();
490 
491 			// name and extension have to coincide
492 			if ( m_pConnection->matchesExtension( sExt ) )
493 			{
494 				if ( !sExt.isEmpty() )
495 					sName = sName.replaceAt(sName.getLength()-(sExt.getLength()+1),sExt.getLength()+1,::rtl::OUString());
496 				if ( sName == m_Name )
497 				{
498 					Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY );
499 					sURL = xContentAccess->queryContentIdentifierString();
500 					break;
501 				}
502 			}
503 		}
504 		xDir->beforeFirst(); // move back to before first record
505 	}
506 	catch(Exception&)
507 	{
508 		OSL_ASSERT(0);
509 	}
510 	return sURL.getStr();
511 }
512 // -------------------------------------------------------------------------
refreshColumns()513 void OFlatTable::refreshColumns()
514 {
515     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::refreshColumns" );
516 	::osl::MutexGuard aGuard( m_aMutex );
517 
518 	TStringVector aVector;
519 	aVector.reserve(m_aColumns->get().size());
520 
521 	for(OSQLColumns::Vector::const_iterator aIter = m_aColumns->get().begin();aIter != m_aColumns->get().end();++aIter)
522 		aVector.push_back(Reference< XNamed>(*aIter,UNO_QUERY)->getName());
523 
524 	if(m_pColumns)
525 		m_pColumns->reFill(aVector);
526 	else
527 		m_pColumns	= new OFlatColumns(this,m_aMutex,aVector);
528 }
529 
530 // -------------------------------------------------------------------------
disposing(void)531 void SAL_CALL OFlatTable::disposing(void)
532 {
533     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::disposing" );
534 	OFileTable::disposing();
535 	::osl::MutexGuard aGuard(m_aMutex);
536 	m_aColumns = NULL;
537 }
538 // -------------------------------------------------------------------------
getTypes()539 Sequence< Type > SAL_CALL OFlatTable::getTypes(  ) throw(RuntimeException)
540 {
541 	Sequence< Type > aTypes = OTable_TYPEDEF::getTypes();
542 	::std::vector<Type> aOwnTypes;
543 	aOwnTypes.reserve(aTypes.getLength());
544 	const Type* pBegin = aTypes.getConstArray();
545 	const Type* pEnd = pBegin + aTypes.getLength();
546 	for(;pBegin != pEnd;++pBegin)
547 	{
548 		if(!(*pBegin == ::getCppuType((const Reference<XKeysSupplier>*)0)	||
549 			*pBegin == ::getCppuType((const Reference<XRename>*)0)			||
550 			*pBegin == ::getCppuType((const Reference<XIndexesSupplier>*)0) ||
551 			*pBegin == ::getCppuType((const Reference<XAlterTable>*)0)		||
552 			*pBegin == ::getCppuType((const Reference<XDataDescriptorFactory>*)0)))
553 		{
554 			aOwnTypes.push_back(*pBegin);
555 		}
556 	}
557 	Type *pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0];
558 	return Sequence< Type >(pTypes, aOwnTypes.size());
559 }
560 
561 // -------------------------------------------------------------------------
queryInterface(const Type & rType)562 Any SAL_CALL OFlatTable::queryInterface( const Type & rType ) throw(RuntimeException)
563 {
564 	if( rType == ::getCppuType((const Reference<XKeysSupplier>*)0)		||
565 		rType == ::getCppuType((const Reference<XIndexesSupplier>*)0)	||
566 		rType == ::getCppuType((const Reference<XRename>*)0)			||
567 		rType == ::getCppuType((const Reference<XAlterTable>*)0)		||
568 		rType == ::getCppuType((const Reference<XDataDescriptorFactory>*)0))
569 		return Any();
570 
571 	Any aRet = OTable_TYPEDEF::queryInterface(rType);
572 	return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< ::com::sun::star::lang::XUnoTunnel*> (this));
573 }
574 
575 //--------------------------------------------------------------------------
getUnoTunnelImplementationId()576 Sequence< sal_Int8 > OFlatTable::getUnoTunnelImplementationId()
577 {
578 	static ::cppu::OImplementationId * pId = 0;
579 	if (! pId)
580 	{
581 		::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
582 		if (! pId)
583 		{
584 			static ::cppu::OImplementationId aId;
585 			pId = &aId;
586 		}
587 	}
588 	return pId->getImplementationId();
589 }
590 
591 // com::sun::star::lang::XUnoTunnel
592 //------------------------------------------------------------------
getSomething(const Sequence<sal_Int8> & rId)593 sal_Int64 OFlatTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException)
594 {
595     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::getSomething" );
596 	return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(),  rId.getConstArray(), 16 ) )
597 				? reinterpret_cast< sal_Int64 >( this )
598 				: OFlatTable_BASE::getSomething(rId);
599 }
600 //------------------------------------------------------------------
fetchRow(OValueRefRow & _rRow,const OSQLColumns & _rCols,sal_Bool bIsTable,sal_Bool bRetrieveData)601 sal_Bool OFlatTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols,sal_Bool bIsTable,sal_Bool bRetrieveData)
602 {
603     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::fetchRow" );
604 	*(_rRow->get())[0] = m_nFilePos;
605 
606 	if (!bRetrieveData)
607 		return sal_True;
608     if ( m_bNeedToReadLine )
609     {
610         sal_Int32 nCurrentPos = 0;
611         m_pFileStream->Seek(m_nFilePos);
612         readLine(nCurrentPos);
613         m_bNeedToReadLine = false;
614     }
615 
616 	OFlatConnection* pConnection = (OFlatConnection*)m_pConnection;
617     const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter();
618 	const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter();
619 	// Felder:
620 	sal_Int32 nStartPos = 0;
621 	::rtl::OUString aStr;
622     OSQLColumns::Vector::const_iterator aIter = _rCols.get().begin();
623     OSQLColumns::Vector::const_iterator aEnd = _rCols.get().end();
624     const OValueRefVector::Vector::size_type nCount = _rRow->get().size();
625 	for (OValueRefVector::Vector::size_type i = 1; aIter != aEnd && i < nCount;
626          ++aIter, i++)
627 	{
628         m_aCurrentLine.GetTokenSpecial(&aStr,nStartPos,m_cFieldDelimiter,m_cStringDelimiter);
629 
630 		if (aStr.isEmpty())
631 			(_rRow->get())[i]->setNull();
632 		else
633 		{
634 			// Laengen je nach Datentyp:
635 			sal_Int32	nLen,
636 						nType = 0;
637 			if(bIsTable)
638 			{
639 				nLen	= m_aPrecisions[i-1];
640 				nType	= m_aTypes[i-1];
641 			}
642 			else
643 			{
644 				Reference< XPropertySet> xColumn = *aIter;
645 				xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION))	>>= nLen;
646 				xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))		>>= nType;
647 			}
648 			switch(nType)
649 			{
650 				case DataType::TIMESTAMP:
651 				case DataType::DATE:
652 				case DataType::TIME:
653 				{
654 					try
655 					{
656 						double nRes = m_xNumberFormatter->convertStringToNumber(::com::sun::star::util::NumberFormat::ALL,aStr);
657 
658 						switch(nType)
659 						{
660 							case DataType::DATE:
661 								*(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes,m_aNullDate));
662 								break;
663 							case DataType::TIMESTAMP:
664 								*(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes,m_aNullDate));
665 								break;
666 							default:
667 								*(_rRow->get())[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes));
668 						}
669 					}
670 					catch(Exception&)
671 					{
672 						(_rRow->get())[i]->setNull();
673 					}
674 				}	break;
675 				case DataType::DOUBLE:
676 				case DataType::INTEGER:
677 				case DataType::DECIMAL:				// #99178# OJ
678 				case DataType::NUMERIC:
679 				{
680 
681 					String aStrConverted;
682                     if ( DataType::INTEGER != nType )
683                     {
684                         sal_Unicode* pData = aStrConverted.AllocBuffer(aStr.getLength());
685                         const sal_Unicode* pStart = pData;
686 
687 					    OSL_ENSURE(cDecimalDelimiter && nType != DataType::INTEGER ||
688 							       !cDecimalDelimiter && nType == DataType::INTEGER,
689 							       "FalscherTyp");
690 
691 					    // In Standard-Notation (DezimalPUNKT ohne Tausender-Komma) umwandeln:
692 					    for (sal_Int32 j = 0; j < aStr.getLength(); ++j)
693 					    {
694                             const sal_Unicode cChar = aStr[j];
695 						    if (cDecimalDelimiter && cChar == cDecimalDelimiter)
696                                 *pData++ = '.';
697 							    //aStrConverted.Append( '.' );
698 						    else if ( cChar == '.' ) // special case, if decimal seperator isn't '.' we have to put the string after it
699 							    continue; // #99189# OJ
700 						    else if (cThousandDelimiter && cChar == cThousandDelimiter)
701 						    {
702 							    // weglassen
703 						    }
704 						    else
705                                 *pData++ = cChar;
706 							    //aStrConverted.Append(cChar);
707 					    } // for (sal_Int32 j = 0; j < aStr.Len(); ++j)
708                         aStrConverted.ReleaseBufferAccess(xub_StrLen(pData - pStart));
709                     } // if ( DataType::INTEGER != nType )
710                     else
711                     {
712                         aStrConverted = aStr;
713                         if ( cThousandDelimiter )
714                             aStrConverted.EraseAllChars(cThousandDelimiter);
715                     }
716 					const double nVal = ::rtl::math::stringToDouble(aStrConverted,'.',',',NULL,NULL);
717 
718 					// #99178# OJ
719 					if ( DataType::DECIMAL == nType || DataType::NUMERIC == nType )
720                         *(_rRow->get())[i] = ::rtl::OUString::valueOf(nVal);
721 					else
722 						*(_rRow->get())[i] = nVal;
723 				} break;
724 
725 				default:
726 				{
727 					// Wert als String in Variable der Row uebernehmen
728 					*(_rRow->get())[i] = ORowSetValue(aStr);
729 				}
730 				break;
731 			} // switch(nType)
732             (_rRow->get())[i]->setTypeKind(nType);
733 		}
734 	}
735 	return sal_True;
736 }
refreshHeader()737 void OFlatTable::refreshHeader()
738 {
739     m_nRowPos = 0;
740 }
741 // -----------------------------------------------------------------------------
seekRow(IResultSetHelper::Movement eCursorPosition,sal_Int32 nOffset,sal_Int32 & nCurPos)742 sal_Bool OFlatTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos)
743 {
744     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::seekRow" );
745 	OSL_ENSURE(m_pFileStream,"OFlatTable::seekRow: FileStream is NULL!");
746 	// ----------------------------------------------------------
747 	// Positionierung vorbereiten:
748 	m_nFilePos = nCurPos;
749 
750 	switch(eCursorPosition)
751 	{
752 		case IResultSetHelper::FIRST:
753 			m_nRowPos = 0;
754             // run through
755 		case IResultSetHelper::NEXT:
756             {
757 			    ++m_nRowPos;
758                 ::std::map<sal_Int32,TRowPositionsInFile::iterator>::const_iterator aFind = m_aRowPosToFilePos.find(m_nRowPos);
759                 m_bNeedToReadLine = aFind != m_aRowPosToFilePos.end();
760                 if ( m_bNeedToReadLine )
761                 {
762                     m_nFilePos  = aFind->second->first;
763                     nCurPos     = aFind->second->second;
764                 } // if ( m_bNeedToReadLine )
765                 else
766                 {
767                     if ( m_nRowPos == 1 )
768                         m_nFilePos = m_nStartRowFilePos;
769 			        m_pFileStream->Seek(m_nFilePos);
770 			        if ( m_pFileStream->IsEof() || !readLine(nCurPos) /*|| !checkHeaderLine()*/)
771 			        {
772 				        m_nMaxRowCount = m_nRowPos -1;
773 				        return sal_False;
774 			        } // if ( m_pFileStream->IsEof() || !readLine(nCurPos) /*|| !checkHeaderLine()*/)
775 
776                     TRowPositionsInFile::iterator aPos = m_aFilePosToEndLinePos.insert(TRowPositionsInFile::value_type(m_nFilePos,nCurPos)).first;
777                     m_aRowPosToFilePos.insert(::std::map<sal_Int32,TRowPositionsInFile::iterator>::value_type(m_nRowPos,aPos));
778                 }
779             }
780 
781 			break;
782 		case IResultSetHelper::PRIOR:
783 			--m_nRowPos;
784 			if(m_nRowPos > 0)
785 			{
786                 TRowPositionsInFile::iterator aPositions = m_aRowPosToFilePos[m_nRowPos];
787 				m_nFilePos = aPositions->first;
788                 nCurPos = aPositions->second;
789                 m_bNeedToReadLine = true;
790 			}
791 			else
792 				m_nRowPos = 0;
793 
794 			break;
795 		case IResultSetHelper::LAST:
796 			if ( m_nMaxRowCount )
797 			{
798                 ::std::map<sal_Int32,TRowPositionsInFile::iterator>::reverse_iterator aLastPos = m_aRowPosToFilePos.rbegin();
799                 m_nRowPos  = aLastPos->first;
800 				m_nFilePos = aLastPos->second->first;
801                 nCurPos    = aLastPos->second->second;
802 
803 				//m_pFileStream->Seek(m_nFilePos);
804                 m_bNeedToReadLine = true;
805 				//if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) )
806 				//	return sal_False;
807 			}
808 			else
809 			{
810 				while(seekRow(IResultSetHelper::NEXT,1,nCurPos)) ; // run through after last row
811 				// now I know all
812 				seekRow(IResultSetHelper::PRIOR,1,nCurPos);
813 			}
814 			break;
815 		case IResultSetHelper::RELATIVE:
816 			if(nOffset > 0)
817 			{
818 				for(sal_Int32 i = 0;i<nOffset;++i)
819 					seekRow(IResultSetHelper::NEXT,1,nCurPos);
820 			}
821 			else if(nOffset < 0)
822 			{
823 				for(sal_Int32 i = nOffset;i;++i)
824 					seekRow(IResultSetHelper::PRIOR,1,nCurPos);
825 			}
826 			break;
827 		case IResultSetHelper::ABSOLUTE:
828 			{
829 				if(nOffset < 0)
830 					nOffset = m_nRowPos + nOffset;
831 				::std::map<sal_Int32,TRowPositionsInFile::iterator>::const_iterator aIter = m_aRowPosToFilePos.find(nOffset);
832 				if(aIter != m_aRowPosToFilePos.end())
833 				{
834 					m_nFilePos  = aIter->second->first;
835                     nCurPos     = aIter->second->second;
836 					//m_pFileStream->Seek(m_nFilePos);
837                     m_bNeedToReadLine = true;
838 					//if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) )
839 					//	return sal_False;
840 				}
841 				else if(m_nMaxRowCount && nOffset > m_nMaxRowCount) // offset is outside the table
842 				{
843 					m_nRowPos = m_nMaxRowCount;
844 					return sal_False;
845 				}
846 				else
847 				{
848 					aIter = m_aRowPosToFilePos.upper_bound(nOffset);
849 					if(aIter == m_aRowPosToFilePos.end())
850 					{
851                         ::std::map<sal_Int32,TRowPositionsInFile::iterator>::reverse_iterator aLastPos = m_aRowPosToFilePos.rbegin();
852 						m_nRowPos	= aLastPos->first;
853 						nCurPos = m_nFilePos = aLastPos->second->first;
854 						while(m_nRowPos != nOffset)
855 							seekRow(IResultSetHelper::NEXT,1,nCurPos);
856 					}
857 					else
858 					{
859 						--aIter;
860 						m_nRowPos	= aIter->first;
861 						m_nFilePos	= aIter->second->first;
862                         nCurPos	    = aIter->second->second;
863 						//m_pFileStream->Seek(m_nFilePos);
864                         m_bNeedToReadLine = true;
865 						//if ( m_pFileStream->IsEof() /*|| !checkHeaderLine()*/ || !readLine(nCurPos) )
866 						//	return sal_False;
867 					}
868 				}
869 			}
870 
871 			break;
872 		case IResultSetHelper::BOOKMARK:
873             {
874                 TRowPositionsInFile::const_iterator aFind = m_aFilePosToEndLinePos.find(nOffset);
875                 m_bNeedToReadLine = aFind != m_aFilePosToEndLinePos.end();
876                 if ( m_bNeedToReadLine )
877                 {
878                     m_nFilePos  = aFind->first;
879                     nCurPos = aFind->second;
880                 }
881                 else
882                 {
883                     m_nFilePos = nOffset;
884                     m_pFileStream->Seek(nOffset);
885 			        if (m_pFileStream->IsEof() || !readLine(nCurPos) )
886 				        return sal_False;
887                 }
888                 break;
889             }
890 	}
891 
892     //nCurPos = m_nFilePos;
893 
894 	return sal_True;
895 }
896 // -----------------------------------------------------------------------------
readLine(sal_Int32 & _rnCurrentPos)897 sal_Bool OFlatTable::readLine(sal_Int32& _rnCurrentPos)
898 {
899     return readLine(m_aCurrentLine, _rnCurrentPos);
900 }
901 // -----------------------------------------------------------------------------
readLine(QuotedTokenizedString & lineOut,sal_Int32 & _rnCurrentPos)902 sal_Bool OFlatTable::readLine(QuotedTokenizedString& lineOut, sal_Int32& _rnCurrentPos)
903 {
904     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "flat", "Ocke.Janssen@sun.com", "OFlatTable::readLine" );
905     const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding();
906     ::rtl::OUStringBuffer lineBuffer( 4096 );
907     ::rtl::OUString separator = ::rtl::OUString();
908     static ::rtl::OUString lf = ::rtl::OUString::createFromAscii( "\n" );
909     bool isFieldStarting = true;
910     bool inQuotedField = false;
911     sal_Bool result = sal_True;
912     do
913     {
914         ::rtl::OUString line;
915         m_pFileStream->ReadByteStringLine(line,nEncoding);
916         if (m_pFileStream->IsEof())
917         {
918             result = sal_False;
919             break;
920         }
921 
922         bool wasPreviousQuote = false;
923         for ( sal_Int32 i = 0; i < line.getLength(); i++ )
924         {
925             sal_Unicode ch = line[i];
926             if ( ch == m_cStringDelimiter )
927             {
928                 if ( isFieldStarting )
929                 {
930                     isFieldStarting = false;
931                     inQuotedField = true;
932                 }
933                 else
934                 {
935                     wasPreviousQuote = !wasPreviousQuote;
936                 }
937             }
938             else if ( ch == m_cFieldDelimiter )
939             {
940                 if ( !inQuotedField )
941                     isFieldStarting = true;
942             }
943             else
944             {
945                 if ( wasPreviousQuote )
946                     inQuotedField = false;
947                 wasPreviousQuote = false;
948             }
949         }
950         if ( wasPreviousQuote )
951             inQuotedField = false;
952 
953         lineBuffer.append( separator );
954         separator = lf;
955         lineBuffer.append( line );
956 
957     } while ( inQuotedField );
958 
959     lineOut = lineBuffer.makeStringAndClear();
960     _rnCurrentPos = m_pFileStream->Tell();
961     return result;
962 }
963