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