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