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