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