1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: LFolderList.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
36 #include "LFolderList.hxx"
37 #include <com/sun/star/sdbc/ColumnValue.hpp>
38 #include <com/sun/star/sdbc/DataType.hpp>
39 #include <svtools/converter.hxx>
40 #include "LConnection.hxx"
41 #include "LColumns.hxx"
42 #include <osl/thread.h>
43 #include <tools/config.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <svtools/zforlist.hxx>
46 #include <rtl/math.hxx>
47 #include <stdio.h> //sprintf
48 #include <comphelper/extract.hxx>
49 #include <comphelper/numbers.hxx>
50 #include "LDriver.hxx"
51 #include <com/sun/star/util/NumberFormat.hpp>
52 #include <unotools/configmgr.hxx>
53 #include <i18npool/mslangid.hxx>
54 #include "connectivity/dbconversion.hxx"
55 #include <comphelper/types.hxx>
56 #include <unotools/ucbstreamhelper.hxx>
57 #include <tools/debug.hxx>
58 #include "connectivity/dbexception.hxx"
59 #ifndef CONNECTIVITY_EVOAB_DEBUG_HELPER_HXX
62 #include <svtools/syslocale.hxx>
64 using namespace ::comphelper
;
65 using namespace connectivity
;
66 using namespace connectivity::evoab
;
67 using namespace connectivity::file
;
68 using namespace ::cppu
;
70 using namespace ::com::sun::star::uno
;
71 using namespace ::com::sun::star::beans
;
72 using namespace ::com::sun::star::sdbcx
;
73 using namespace ::com::sun::star::sdbc
;
74 using namespace ::com::sun::star::container
;
75 using namespace ::com::sun::star::lang
;
77 // -------------------------------------------------------------------------
78 void OEvoabFolderList::fillColumns(const ::com::sun::star::lang::Locale
& _aLocale
)
82 QuotedTokenizedString aHeaderLine
;
83 OEvoabConnection
* pConnection
= (OEvoabConnection
*)m_pConnection
;
86 QuotedTokenizedString aFirstLine
;
87 bRead
= m_pFileStream
->ReadByteStringLine(aFirstLine
,pConnection
->getTextEncoding());
89 while(bRead
&& !aFirstLine
.Len())
91 bRead
= m_pFileStream
->ReadByteStringLine(aFirstLine
,pConnection
->getTextEncoding());
93 // use first row as headerline because we need the number of columns
94 aHeaderLine
= aFirstLine
;
97 xub_StrLen nFieldCount
= aHeaderLine
.GetTokenCount(pConnection
->getFieldDelimiter(),pConnection
->getStringDelimiter());
99 if(!m_aColumns
.isValid())
100 m_aColumns
= new OSQLColumns();
102 m_aColumns
->get().clear();
105 m_aPrecisions
.clear();
107 // reserve some space
108 m_aColumns
->get().reserve(nFieldCount
);
109 m_aTypes
.reserve(nFieldCount
);
110 m_aPrecisions
.reserve(nFieldCount
);
111 m_aScales
.reserve(nFieldCount
);
113 sal_Bool bCase
= getConnection()->getMetaData()->storesMixedCaseQuotedIdentifiers();
114 CharClass
aCharClass(pConnection
->getDriver()->getFactory(),_aLocale
);
116 sal_Unicode cDecimalDelimiter
= pConnection
->getDecimalDelimiter();
117 sal_Unicode cThousandDelimiter
= pConnection
->getThousandDelimiter();
119 ::rtl::OUString aTypeName
;
120 ::comphelper::UStringMixEqual
aCase(bCase
);
121 xub_StrLen nStartPosFirstLine
= 0; // use for eficient way to get the tokens
122 xub_StrLen nStartPosFirstLine2
= 0;
123 for (xub_StrLen i
= 0; i
< nFieldCount
; i
++)
126 // no column name so ...
128 aColumnName
+= String::CreateFromInt32(i
+1);
131 UINT16 nPrecision
= 0;
134 BOOL bNumeric
= FALSE
;
137 // first without fielddelimiter
139 aFirstLine
.GetTokenSpecial(aField
,nStartPosFirstLine
,pConnection
->getFieldDelimiter(),'\0');
140 if (aField
.Len() == 0 ||
141 (pConnection
->getStringDelimiter() && pConnection
->getStringDelimiter() == aField
.GetChar(0)))
148 if ( pConnection
->getStringDelimiter() != '\0' )
149 aFirstLine
.GetTokenSpecial(aField2
,nStartPosFirstLine2
,pConnection
->getFieldDelimiter(),pConnection
->getStringDelimiter());
153 if (aField2
.Len() == 0)
161 for (xub_StrLen j
= 0; j
< aField2
.Len(); j
++)
163 sal_Unicode c
= aField2
.GetChar(j
);
164 // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen?
165 if ((!cDecimalDelimiter
|| c
!= cDecimalDelimiter
) &&
166 (!cThousandDelimiter
|| c
!= cThousandDelimiter
) &&
167 !aCharClass
.isDigit(aField2
,j
))
172 if (cDecimalDelimiter
&& c
== cDecimalDelimiter
)
174 nPrecision
= 15; // we have an decimal value
180 if (nDot
> 1) // if there is more than one dot it isn't a number
182 if (bNumeric
&& cThousandDelimiter
)
184 // Ist der Trenner richtig angegeben?
185 String aValue
= aField2
.GetToken(0,cDecimalDelimiter
);
186 for (sal_Int32 j
= aValue
.Len() - 4; j
>= 0; j
-= 4)
188 sal_Unicode c
= aValue
.GetChar(j
);
189 // nur Ziffern und Dezimalpunkt und Tausender-Trennzeichen?
190 if (c
== cThousandDelimiter
&& j
)
200 // jetzt koennte es noch ein Datumsfeld sein
205 nIndex
= m_xNumberFormatter
->detectNumberFormat(::com::sun::star::util::NumberFormat::ALL
,aField2
);
214 sal_Int32 nFlags
= 0;
217 if (cDecimalDelimiter
)
221 eType
= DataType::DECIMAL
;
222 aTypeName
= ::rtl::OUString::createFromAscii("DECIMAL");
226 eType
= DataType::DOUBLE
;
227 aTypeName
= ::rtl::OUString::createFromAscii("DOUBLE");
231 eType
= DataType::INTEGER
;
232 nFlags
= ColumnSearch::BASIC
;
237 switch (comphelper::getNumberFormatType(m_xNumberFormatter
,nIndex
))
239 case NUMBERFORMAT_DATE
:
240 eType
= DataType::DATE
;
241 aTypeName
= ::rtl::OUString::createFromAscii("DATE");
243 case NUMBERFORMAT_DATETIME
:
244 eType
= DataType::TIMESTAMP
;
245 aTypeName
= ::rtl::OUString::createFromAscii("TIMESTAMP");
247 case NUMBERFORMAT_TIME
:
248 eType
= DataType::TIME
;
249 aTypeName
= ::rtl::OUString::createFromAscii("TIME");
252 eType
= DataType::VARCHAR
;
253 nPrecision
= 0; // nyi: Daten koennen aber laenger sein!
255 aTypeName
= ::rtl::OUString::createFromAscii("VARCHAR");
257 nFlags
|= ColumnSearch::CHAR
;
260 // check if the columname already exists
261 String
aAlias(aColumnName
);
262 OSQLColumns::Vector::const_iterator aFind
= connectivity::find(m_aColumns
->get().begin(),m_aColumns
->get().end(),aAlias
,aCase
);
263 sal_Int32 nExprCnt
= 0;
264 while(aFind
!= m_aColumns
->get().end())
266 (aAlias
= aColumnName
) += String::CreateFromInt32(++nExprCnt
);
267 aFind
= connectivity::find(m_aColumns
->get().begin(),m_aColumns
->get().end(),aAlias
,aCase
);
270 sdbcx::OColumn
* pColumn
= new sdbcx::OColumn(aAlias
,aTypeName
,::rtl::OUString(),
271 ColumnValue::NULLABLE
,
279 Reference
< XPropertySet
> xCol
= pColumn
;
280 m_aColumns
->get().push_back(xCol
);
281 m_aTypes
.push_back(eType
);
282 m_aPrecisions
.push_back(nPrecision
);
283 m_aScales
.push_back(nScale
);
285 m_pFileStream
->Seek(STREAM_SEEK_TO_BEGIN
);
287 // -------------------------------------------------------------------------
288 DBG_NAME( OEvoabFolderList
);
289 OEvoabFolderList::OEvoabFolderList(OEvoabConnection
* _pConnection
)
292 ,m_pConnection(_pConnection
)
293 ,m_bIsNull(sal_False
)
295 DBG_CTOR( OEvoabFolderList
, NULL
);
296 m_aColumns
= new OSQLColumns();
300 // -----------------------------------------------------------------------------
301 void OEvoabFolderList::construct()
303 SvtSysLocale aLocale
;
304 ::com::sun::star::lang::Locale
aAppLocale(aLocale
.GetLocaleDataPtr()->getLocale());
305 Sequence
< ::com::sun::star::uno::Any
> aArg(1);
306 aArg
[0] <<= aAppLocale
;
308 Reference
< ::com::sun::star::util::XNumberFormatsSupplier
> xSupplier(m_pConnection
->getDriver()->getFactory()->createInstanceWithArguments(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatsSupplier"),aArg
),UNO_QUERY
);
309 m_xNumberFormatter
= Reference
< ::com::sun::star::util::XNumberFormatter
>(m_pConnection
->getDriver()->getFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatter")),UNO_QUERY
);
310 m_xNumberFormatter
->attachNumberFormatsSupplier(xSupplier
);
313 aURL
.SetURL(m_pConnection
->getDriver()->getEvoFolderListFileURL());
315 String aFileName
= aURL
.GetMainURL(INetURLObject::NO_DECODE
);
317 EVO_TRACE_STRING("OJ::construct()::aFileName = %s\n", aFileName
);
318 m_pFileStream
= createStream_simpleError( aFileName
,STREAM_READWRITE
| STREAM_NOCREATE
| STREAM_SHARE_DENYWRITE
);
321 m_pFileStream
= createStream_simpleError( aFileName
,STREAM_READ
| STREAM_NOCREATE
| STREAM_SHARE_DENYNONE
);
325 m_pFileStream
->Seek(STREAM_SEEK_TO_END
);
326 sal_Int32 nSize
= m_pFileStream
->Tell();
327 m_pFileStream
->Seek(STREAM_SEEK_TO_BEGIN
);
329 // Buffersize abhaengig von der Filegroesse
330 m_pFileStream
->SetBufferSize(nSize
> 1000000 ? 32768 :
331 nSize
> 100000 ? 16384 :
332 nSize
> 10000 ? 4096 : 1024);
333 OSL_TRACE("OEvoabFolderList::construct()::m_pFileStream->Tell() = %d\n", nSize
);
335 fillColumns(aAppLocale
);
340 //------------------------------------------------------------------
341 sal_Bool
OEvoabFolderList::fetchRow(OValueRow _rRow
,const OSQLColumns
& _rCols
)
343 (_rRow
->get())[0] = m_nFilePos
; // the "bookmark"
345 OEvoabConnection
* pConnection
= (OEvoabConnection
*)m_pConnection
;
347 xub_StrLen nStartPos
= 0;
349 OSQLColumns::Vector::const_iterator aIter
= _rCols
.get().begin();
350 for (sal_Int32 i
= 0; aIter
!= _rCols
.get().end();++aIter
, ++i
)
352 m_aCurrentLine
.GetTokenSpecial(aStr
,nStartPos
,pConnection
->getFieldDelimiter(),pConnection
->getStringDelimiter());
353 //OSL_TRACE("OEvoabFolderList::fetchRow()::aStr = %s\n", ((OUtoCStr(::rtl::OUString(aStr))) ? (OUtoCStr(::rtl::OUString(aStr))):("NULL")) );
356 (_rRow
->get())[i
+1].setNull();
359 // length depending on the data type
360 sal_Int32 nType
= m_aTypes
[i
];
363 case DataType::TIMESTAMP
:
370 nRes
= m_xNumberFormatter
->convertStringToNumber(::com::sun::star::util::NumberFormat::ALL
,aStr
);
371 Reference
<XPropertySet
> xProp(m_xNumberFormatter
->getNumberFormatsSupplier()->getNumberFormatSettings(),UNO_QUERY
);
372 com::sun::star::util::Date aDate
;
373 xProp
->getPropertyValue(::rtl::OUString::createFromAscii("NullDate")) >>= aDate
;
378 (_rRow
->get())[i
+1] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes
,aDate
));
380 case DataType::TIMESTAMP
:
381 (_rRow
->get())[i
+1] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes
,aDate
));
384 (_rRow
->get())[i
+1] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes
));
389 (_rRow
->get())[i
+1].setNull();
392 case DataType::DOUBLE
:
393 case DataType::INTEGER
:
394 case DataType::DECIMAL
: // #99178# OJ
395 case DataType::NUMERIC
:
397 sal_Unicode cDecimalDelimiter
= pConnection
->getDecimalDelimiter();
398 sal_Unicode cThousandDelimiter
= pConnection
->getThousandDelimiter();
399 String aStrConverted
;
401 OSL_ENSURE(cDecimalDelimiter
&& nType
!= DataType::INTEGER
||
402 !cDecimalDelimiter
&& nType
== DataType::INTEGER
,
405 // In Standard-Notation (DezimalPUNKT ohne Tausender-Komma) umwandeln:
406 for (xub_StrLen j
= 0; j
< aStr
.Len(); ++j
)
408 if (cDecimalDelimiter
&& aStr
.GetChar(j
) == cDecimalDelimiter
)
409 aStrConverted
+= '.';
410 else if ( aStr
.GetChar(j
) == '.' ) // special case, if decimal seperator isn't '.' we have to vut the string after it
412 else if (cThousandDelimiter
&& aStr
.GetChar(j
) == cThousandDelimiter
)
417 aStrConverted
+= aStr
.GetChar(j
) ;
419 double nVal
= ::rtl::math::stringToDouble(aStrConverted
.GetBuffer(),',','.',NULL
,NULL
);
422 if ( DataType::DECIMAL
== nType
|| DataType::NUMERIC
== nType
)
423 (_rRow
->get())[i
+1] = String::CreateFromDouble(nVal
);
425 (_rRow
->get())[i
+1] = nVal
;
430 // Wert als String in Variable der Row uebernehmen
431 (_rRow
->get())[i
+1] = aStr
;
441 //------------------------------------------------------------------
442 sal_Bool
OEvoabFolderList::seekRow(IResultSetHelper::Movement eCursorPosition
)
444 //OSL_TRACE("OEvoabFolderList::seekRow()::(before SeekRow)m_aCurrentLine = %d\n", ((OUtoCStr(::rtl::OUString(m_aCurrentLine))) ? (OUtoCStr(::rtl::OUString(m_aCurrentLine))):("NULL")) );
446 if ( !m_pFileStream
)
448 OEvoabConnection
* pConnection
= (OEvoabConnection
*)m_pConnection
;
449 // ----------------------------------------------------------
450 // Positionierung vorbereiten:
451 //OSL_TRACE("OEvoabFolderList::seekRow()::(before SeekRow,m_pFileStriam Exist)m_aCurrentLine = %d\n", ((OUtoCStr(::rtl::OUString(m_aCurrentLine))) ? (OUtoCStr(::rtl::OUString(m_aCurrentLine))):("NULL")) );
453 switch(eCursorPosition
)
455 case IResultSetHelper::FIRST
:
459 case IResultSetHelper::NEXT
:
460 m_pFileStream
->Seek(m_nFilePos
);
462 if (m_pFileStream
->IsEof())
464 OSL_TRACE( "OEvoabFolderList::seekRow: EOF /before/ reading the line." );
468 m_pFileStream
->ReadByteStringLine(m_aCurrentLine
,pConnection
->getTextEncoding());
469 if (m_pFileStream
->IsEof())
471 OSL_TRACE( "OEvoabFolderList::seekRow: EOF /after/ reading the line." );
472 if ( !m_aCurrentLine
.Len() )
474 OSL_TRACE( "OEvoabFolderList::seekRow: empty line read." );
478 m_nFilePos
= m_pFileStream
->Tell();
482 OSL_ENSURE( sal_False
, "OEvoabFolderList::seekRow: unsupported positioning!" );
486 //OSL_TRACE("OEvoabFolderList::seekRow()::(after SeekRow)m_aCurrentLine = %d\n", ((OUtoCStr(::rtl::OUString(m_aCurrentLine))) ? (OUtoCStr(::rtl::OUString(m_aCurrentLine))):("NULL")) );
490 // -----------------------------------------------------------------------------
491 SvStream
* OEvoabFolderList::createStream_simpleError( const String
& _rFileName
, StreamMode _eOpenMode
)
493 utl::UcbLockBytesHandler
* p_null_dummy
=NULL
;
494 SvStream
* pReturn
= ::utl::UcbStreamHelper::CreateStream( _rFileName
, _eOpenMode
, p_null_dummy
);
495 if (pReturn
&& (ERRCODE_NONE
!= pReturn
->GetErrorCode()))
502 // -----------------------------------------------------------------------------
503 const ORowSetValue
& OEvoabFolderList::getValue(sal_Int32 _nColumnIndex
) throw(::com::sun::star::sdbc::SQLException
)
505 checkIndex( _nColumnIndex
);
507 m_bIsNull
= (m_aRow
->get())[_nColumnIndex
].isNull();
508 return (m_aRow
->get())[_nColumnIndex
];
510 // -----------------------------------------------------------------------------
511 void OEvoabFolderList::checkIndex(sal_Int32 _nColumnIndex
) throw(::com::sun::star::sdbc::SQLException
)
513 if ( _nColumnIndex
<= 0 || _nColumnIndex
>= (sal_Int32
)m_aRow
->get().size() ) {
514 // ::dbtools::throwInvalidIndexException();
518 // -------------------------------------------------------------------------
519 ::rtl::OUString SAL_CALL
OEvoabFolderList::getString( sal_Int32 _nColumnIndex
) throw(SQLException
, RuntimeException
)
521 return getValue(_nColumnIndex
);
523 // -------------------------------------------------------------------------
524 sal_Int32 SAL_CALL
OEvoabFolderList::getInt( sal_Int32 _nColumnIndex
) throw(SQLException
, RuntimeException
)
526 return getValue( _nColumnIndex
);
528 // -----------------------------------------------------------------------------
529 void OEvoabFolderList::initializeRow(sal_Int32 _nColumnCount
)
531 if(!m_aRow
.isValid())
533 m_aRow
= new OValueVector(_nColumnCount
);
534 (m_aRow
->get())[0].setBound(sal_True
);
535 ::std::for_each(m_aRow
->get().begin()+1,m_aRow
->get().end(),TSetBound(sal_False
));
537 //OSL_TRACE("OEvoabFolderList::initializeRow()::_nColumnCount = %d\n", _nColumnCount);
540 // -------------------------------------------------------------------------
542 sal_Bool SAL_CALL
OEvoabFolderList::first( ) throw(SQLException
, RuntimeException
)
544 sal_Bool bSuccess
= seekRow(IResultSetHelper::FIRST
);
546 EVO_TRACE_STRING("OEvoabFolderList::first(): returning %s\n", ::rtl::OUString::valueOf(bSuccess
) );
549 // -------------------------------------------------------------------------
551 sal_Bool SAL_CALL
OEvoabFolderList::next( ) throw(SQLException
, RuntimeException
)
553 sal_Bool bSuccess
= seekRow(IResultSetHelper::NEXT
);
555 EVO_TRACE_STRING("OEvoabFolderList::next(): returning %s\n", ::rtl::OUString::valueOf(bSuccess
) );
558 // -------------------------------------------------------------------------
560 sal_Int32 SAL_CALL
OEvoabFolderList::getRow( ) throw(SQLException
, RuntimeException
)
562 sal_Bool bRet
= fetchRow(m_aRow
,getTableColumns().getBody());
563 EVO_TRACE_STRING("OEvoabFolderList::getRow()::fetchRow() = %s\n", ::rtl::OUString::valueOf(bRet
) );