1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <dbase/DTable.hxx>
21 #include <com/sun/star/container/ElementExistException.hpp>
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 <com/sun/star/sdbc/XRow.hpp>
26 #include <o3tl/safeint.hxx>
27 #include <svl/converter.hxx>
28 #include <dbase/DConnection.hxx>
29 #include <dbase/DColumns.hxx>
30 #include <tools/config.hxx>
31 #include <tools/diagnose_ex.h>
32 #include <dbase/DIndex.hxx>
33 #include <dbase/DIndexes.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <rtl/math.hxx>
36 #include <ucbhelper/content.hxx>
37 #include <com/sun/star/ucb/ContentCreationException.hpp>
38 #include <connectivity/dbexception.hxx>
39 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
40 #include <comphelper/property.hxx>
41 #include <comphelper/servicehelper.hxx>
42 #include <comphelper/string.hxx>
43 #include <unotools/tempfile.hxx>
44 #include <unotools/ucbhelper.hxx>
45 #include <comphelper/types.hxx>
46 #include <cppuhelper/typeprovider.hxx>
47 #include <cppuhelper/exc_hlp.hxx>
48 #include <cppuhelper/queryinterface.hxx>
49 #include <connectivity/dbtools.hxx>
50 #include <connectivity/FValue.hxx>
51 #include <connectivity/dbconversion.hxx>
52 #include <connectivity/sdbcx/VColumn.hxx>
53 #include <strings.hrc>
54 #include <rtl/strbuf.hxx>
55 #include <sal/log.hxx>
56 #include <tools/date.hxx>
61 #include <string_view>
63 using namespace ::comphelper
;
64 using namespace connectivity
;
65 using namespace connectivity::sdbcx
;
66 using namespace connectivity::dbase
;
67 using namespace connectivity::file
;
68 using namespace ::ucbhelper
;
69 using namespace ::utl
;
70 using namespace ::cppu
;
71 using namespace ::dbtools
;
72 using namespace ::com::sun::star::uno
;
73 using namespace ::com::sun::star::ucb
;
74 using namespace ::com::sun::star::beans
;
75 using namespace ::com::sun::star::sdbcx
;
76 using namespace ::com::sun::star::sdbc
;
77 using namespace ::com::sun::star::container
;
78 using namespace ::com::sun::star::lang
;
79 using namespace ::com::sun::star::i18n
;
81 // stored as the Field Descriptor terminator
82 #define FIELD_DESCRIPTOR_TERMINATOR 0x0D
87 std::size_t lcl_getFileSize(SvStream
& _rStream
)
89 std::size_t nFileSize
= 0;
90 _rStream
.Seek(STREAM_SEEK_TO_END
);
93 _rStream
.ReadChar( cEOL
);
94 nFileSize
= _rStream
.Tell();
95 if ( cEOL
== DBF_EOL
)
100 calculates the Julian date
102 void lcl_CalcJulDate(sal_Int32
& _nJulianDate
,sal_Int32
& _nJulianTime
, const css::util::DateTime
& rDateTime
)
104 css::util::DateTime aDateTime
= rDateTime
;
106 if (aDateTime
.Month
> 12)
109 sal_uInt16 delta
= rDateTime
.Month
/ 12;
110 aDateTime
.Year
+= delta
;
111 aDateTime
.Month
-= delta
* 12;
115 _nJulianTime
= ((aDateTime
.Hours
*3600000)+(aDateTime
.Minutes
*60000)+(aDateTime
.Seconds
*1000)+(aDateTime
.NanoSeconds
/1000000));
116 /* conversion factors */
119 if ( aDateTime
.Month
<= 2 )
121 iy0
= aDateTime
.Year
- 1;
122 im0
= aDateTime
.Month
+ 12;
126 iy0
= aDateTime
.Year
;
127 im0
= aDateTime
.Month
;
129 sal_Int32 ia
= iy0
/ 100;
130 sal_Int32 ib
= 2 - ia
+ (ia
>> 2);
131 /* calculate julian date */
132 if ( aDateTime
.Year
<= 0 )
134 _nJulianDate
= static_cast<sal_Int32
>((365.25 * iy0
) - 0.75)
135 + static_cast<sal_Int32
>(30.6001 * (im0
+ 1) )
136 + aDateTime
.Day
+ 1720994;
137 } // if ( rDateTime.Year <= 0 )
140 _nJulianDate
= static_cast<sal_Int32
>(365.25 * iy0
)
141 + static_cast<sal_Int32
>(30.6001 * (im0
+ 1))
142 + aDateTime
.Day
+ 1720994;
144 double JD
= _nJulianDate
+ 0.5;
145 _nJulianDate
= static_cast<sal_Int32
>( JD
+ 0.5);
146 const double gyr
= aDateTime
.Year
+ (0.01 * aDateTime
.Month
) + (0.0001 * aDateTime
.Day
);
147 if ( gyr
>= 1582.1015 ) /* on or after 15 October 1582 */
152 calculates date time from the Julian Date
154 void lcl_CalDate(sal_Int32 _nJulianDate
,sal_Int32 _nJulianTime
,css::util::DateTime
& _rDateTime
)
158 sal_Int32 ka
= _nJulianDate
;
159 if ( _nJulianDate
>= 2299161 )
161 sal_Int32 ialp
= static_cast<sal_Int32
>( (static_cast<double>(_nJulianDate
) - 1867216.25 ) / 36524.25 );
162 ka
= _nJulianDate
+ 1 + ialp
- ( ialp
>> 2 );
164 sal_Int32 kb
= ka
+ 1524;
165 sal_Int32 kc
= static_cast<sal_Int32
>( (static_cast<double>(kb
) - 122.1 ) / 365.25 );
166 sal_Int32 kd
= static_cast<sal_Int32
>(static_cast<double>(kc
) * 365.25);
167 sal_Int32 ke
= static_cast<sal_Int32
>(static_cast<double>( kb
- kd
) / 30.6001 );
168 _rDateTime
.Day
= static_cast<sal_uInt16
>(kb
- kd
- static_cast<sal_Int32
>( static_cast<double>(ke
) * 30.6001 ));
170 _rDateTime
.Month
= static_cast<sal_uInt16
>(ke
- 13);
172 _rDateTime
.Month
= static_cast<sal_uInt16
>(ke
- 1);
173 if ( (_rDateTime
.Month
== 2) && (_rDateTime
.Day
> 28) )
175 if ( (_rDateTime
.Month
== 2) && (_rDateTime
.Day
== 29) && (ke
== 3) )
176 _rDateTime
.Year
= static_cast<sal_uInt16
>(kc
- 4716);
177 else if ( _rDateTime
.Month
> 2 )
178 _rDateTime
.Year
= static_cast<sal_uInt16
>(kc
- 4716);
180 _rDateTime
.Year
= static_cast<sal_uInt16
>(kc
- 4715);
185 double d_s
= _nJulianTime
/ 1000.0;
186 double d_m
= d_s
/ 60.0;
187 double d_h
= d_m
/ 60.0;
188 _rDateTime
.Hours
= static_cast<sal_uInt16
>(d_h
);
189 _rDateTime
.Minutes
= static_cast<sal_uInt16
>((d_h
- static_cast<double>(_rDateTime
.Hours
)) * 60.0);
190 _rDateTime
.Seconds
= static_cast<sal_uInt16
>(((d_m
- static_cast<double>(_rDateTime
.Minutes
)) * 60.0)
191 - (static_cast<double>(_rDateTime
.Hours
) * 3600.0));
198 void ODbaseTable::readHeader()
200 OSL_ENSURE(m_pFileStream
,"No Stream available!");
203 m_pFileStream
->RefreshBuffer(); // Make sure, that the header information actually is read again
204 m_pFileStream
->Seek(STREAM_SEEK_TO_BEGIN
);
207 m_pFileStream
->ReadUChar( nType
);
208 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
209 throwInvalidDbaseFormat();
211 m_pFileStream
->ReadBytes(m_aHeader
.dateElems
, 3);
212 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
213 throwInvalidDbaseFormat();
215 m_pFileStream
->ReadUInt32( m_aHeader
.nbRecords
);
216 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
217 throwInvalidDbaseFormat();
219 m_pFileStream
->ReadUInt16( m_aHeader
.headerLength
);
220 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
221 throwInvalidDbaseFormat();
223 m_pFileStream
->ReadUInt16( m_aHeader
.recordLength
);
224 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
225 throwInvalidDbaseFormat();
226 if (m_aHeader
.recordLength
== 0)
227 throwInvalidDbaseFormat();
229 m_pFileStream
->ReadBytes(m_aHeader
.trailer
, 20);
230 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
231 throwInvalidDbaseFormat();
234 if ( ( ( m_aHeader
.headerLength
- 1 ) / 32 - 1 ) <= 0 ) // number of fields
237 throwInvalidDbaseFormat();
241 // Consistency check of the header:
242 m_aHeader
.type
= static_cast<DBFType
>(nType
);
243 switch (m_aHeader
.type
)
249 case VisualFoxProAuto
:
255 m_pFileStream
->SetEndian(SvStreamEndian::LITTLE
);
256 if( getConnection()->isTextEncodingDefaulted() &&
257 !dbfDecodeCharset(m_eEncoding
, nType
, m_aHeader
.trailer
[17]))
259 m_eEncoding
= RTL_TEXTENCODING_IBM_850
;
263 m_pFileStream
->SetEndian(SvStreamEndian::LITTLE
);
267 throwInvalidDbaseFormat();
273 void ODbaseTable::fillColumns()
275 m_pFileStream
->Seek(STREAM_SEEK_TO_BEGIN
);
276 if (!checkSeek(*m_pFileStream
, 32))
278 SAL_WARN("connectivity.drivers", "ODbaseTable::fillColumns: bad offset!");
283 m_aColumns
= new OSQLColumns();
288 m_aPrecisions
.clear();
292 sal_Int32 nFieldCount
= (m_aHeader
.headerLength
- 1) / 32 - 1;
293 if (nFieldCount
<= 0)
295 SAL_WARN("connectivity.drivers", "No columns in table!");
299 auto nRemainingsize
= m_pFileStream
->remainingSize();
300 auto nMaxPossibleRecords
= nRemainingsize
/ 32;
301 if (o3tl::make_unsigned(nFieldCount
) > nMaxPossibleRecords
)
303 SAL_WARN("connectivity.drivers", "Parsing error: " << nMaxPossibleRecords
<<
304 " max possible entries, but " << nFieldCount
<< " claimed, truncating");
305 nFieldCount
= nMaxPossibleRecords
;
308 m_aColumns
->reserve(nFieldCount
);
309 m_aTypes
.reserve(nFieldCount
);
310 m_aPrecisions
.reserve(nFieldCount
);
311 m_aScales
.reserve(nFieldCount
);
314 const bool bCase
= getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
315 const bool bFoxPro
= m_aHeader
.type
== VisualFoxPro
|| m_aHeader
.type
== VisualFoxProAuto
|| m_aHeader
.type
== FoxProMemo
;
318 for (; i
< nFieldCount
; i
++)
320 DBFColumn aDBFColumn
;
321 m_pFileStream
->ReadBytes(aDBFColumn
.db_fnm
, 11);
322 m_pFileStream
->ReadUChar(aDBFColumn
.db_typ
);
323 m_pFileStream
->ReadUInt32(aDBFColumn
.db_adr
);
324 m_pFileStream
->ReadUChar(aDBFColumn
.db_flng
);
325 m_pFileStream
->ReadUChar(aDBFColumn
.db_dez
);
326 m_pFileStream
->ReadBytes(aDBFColumn
.db_free2
, 14);
327 if (!m_pFileStream
->good())
329 SAL_WARN("connectivity.drivers", "ODbaseTable::fillColumns: short read!");
332 if ( FIELD_DESCRIPTOR_TERMINATOR
== aDBFColumn
.db_fnm
[0] ) // 0x0D stored as the Field Descriptor terminator.
335 aDBFColumn
.db_fnm
[sizeof(aDBFColumn
.db_fnm
)-1] = 0; //ensure null termination for broken input
336 const OUString
aColumnName(reinterpret_cast<char *>(aDBFColumn
.db_fnm
), strlen(reinterpret_cast<char *>(aDBFColumn
.db_fnm
)), m_eEncoding
);
338 bool bIsRowVersion
= bFoxPro
&& ( aDBFColumn
.db_free2
[0] & 0x01 ) == 0x01;
340 m_aRealFieldLengths
.push_back(aDBFColumn
.db_flng
);
341 sal_Int32 nPrecision
= aDBFColumn
.db_flng
;
343 bool bIsCurrency
= false;
346 cType
[0] = aDBFColumn
.db_typ
;
348 aTypeName
= OUString(cType
, 1, RTL_TEXTENCODING_ASCII_US
);
349 SAL_INFO( "connectivity.drivers","column type: " << aDBFColumn
.db_typ
);
351 switch (aDBFColumn
.db_typ
)
354 eType
= DataType::VARCHAR
;
355 aTypeName
= "VARCHAR";
359 aTypeName
= "DECIMAL";
360 if ( aDBFColumn
.db_typ
== 'N' )
361 aTypeName
= "NUMERIC";
362 eType
= DataType::DECIMAL
;
364 // for numeric fields two characters more are written, then the precision of the column description predescribes,
365 // to keep room for the possible sign and the comma. This has to be considered...
366 nPrecision
= SvDbaseConverter::ConvertPrecisionToOdbc(nPrecision
,aDBFColumn
.db_dez
);
367 // This is not true for older versions...
370 eType
= DataType::BIT
;
371 aTypeName
= "BOOLEAN";
375 eType
= DataType::DOUBLE
;
376 aTypeName
= "DOUBLE";
379 eType
= DataType::DATE
;
383 eType
= DataType::TIMESTAMP
;
384 aTypeName
= "TIMESTAMP";
387 eType
= DataType::INTEGER
;
388 aTypeName
= "INTEGER";
391 if ( bFoxPro
&& ( aDBFColumn
.db_free2
[0] & 0x04 ) == 0x04 )
393 eType
= DataType::LONGVARBINARY
;
394 aTypeName
= "LONGVARBINARY";
398 aTypeName
= "LONGVARCHAR";
399 eType
= DataType::LONGVARCHAR
;
401 nPrecision
= 2147483647;
404 aTypeName
= "LONGVARBINARY";
405 eType
= DataType::LONGVARBINARY
;
406 nPrecision
= 2147483647;
410 if ( m_aHeader
.type
== VisualFoxPro
|| m_aHeader
.type
== VisualFoxProAuto
)
412 aTypeName
= "DOUBLE";
413 eType
= DataType::DOUBLE
;
417 aTypeName
= "LONGVARBINARY";
418 eType
= DataType::LONGVARBINARY
;
419 nPrecision
= 2147483647;
423 eType
= DataType::OTHER
;
426 m_aTypes
.push_back(eType
);
427 m_aPrecisions
.push_back(nPrecision
);
428 m_aScales
.push_back(aDBFColumn
.db_dez
);
430 Reference
< XPropertySet
> xCol
= new sdbcx::OColumn(aColumnName
,
434 ColumnValue::NULLABLE
,
442 m_CatalogName
, getSchema(), getName());
443 m_aColumns
->push_back(xCol
);
444 } // for (; i < nFieldCount; i++)
445 OSL_ENSURE(i
,"No columns in table!");
448 ODbaseTable::ODbaseTable(sdbcx::OCollection
* _pTables
, ODbaseConnection
* _pConnection
)
449 : ODbaseTable_BASE(_pTables
,_pConnection
)
451 // initialize the header
452 m_aHeader
.type
= dBaseIII
;
453 m_eEncoding
= getConnection()->getTextEncoding();
456 ODbaseTable::ODbaseTable(sdbcx::OCollection
* _pTables
, ODbaseConnection
* _pConnection
,
457 const OUString
& Name
,
458 const OUString
& Type
,
459 const OUString
& Description
,
460 const OUString
& SchemaName
,
461 const OUString
& CatalogName
)
462 : ODbaseTable_BASE(_pTables
,_pConnection
,Name
,
468 m_eEncoding
= getConnection()->getTextEncoding();
472 void ODbaseTable::construct()
474 // initialize the header
475 m_aHeader
.type
= dBaseIII
;
476 m_aHeader
.nbRecords
= 0;
477 m_aHeader
.headerLength
= 0;
478 m_aHeader
.recordLength
= 0;
479 m_aMemoHeader
.db_size
= 0;
481 OUString
sFileName(getEntry(m_pConnection
, m_Name
));
484 aURL
.SetURL(sFileName
);
486 OSL_ENSURE( m_pConnection
->matchesExtension( aURL
.getExtension() ),
487 "ODbaseTable::ODbaseTable: invalid extension!");
488 // getEntry is expected to ensure the correct file name
490 m_pFileStream
= createStream_simpleError( sFileName
, StreamMode::READWRITE
| StreamMode::NOCREATE
| StreamMode::SHARE_DENYWRITE
);
491 m_bWriteable
= ( m_pFileStream
!= nullptr );
493 if ( !m_pFileStream
)
495 m_bWriteable
= false;
496 m_pFileStream
= createStream_simpleError( sFileName
, StreamMode::READ
| StreamMode::NOCREATE
| StreamMode::SHARE_DENYNONE
);
504 std::size_t nFileSize
= lcl_getFileSize(*m_pFileStream
);
506 if (m_aHeader
.headerLength
> nFileSize
)
508 SAL_WARN("connectivity.drivers", "Parsing error: " << nFileSize
<<
509 " max possible size, but " << m_aHeader
.headerLength
<< " claimed, abandoning");
513 if (m_aHeader
.recordLength
)
515 std::size_t nMaxPossibleRecords
= (nFileSize
- m_aHeader
.headerLength
) / m_aHeader
.recordLength
;
516 // #i83401# seems to be empty or someone wrote nonsense into the dbase
517 // file try and recover if m_aHeader.db_slng is sane
518 if (m_aHeader
.nbRecords
== 0)
520 SAL_WARN("connectivity.drivers", "Parsing warning: 0 records claimed, recovering");
521 m_aHeader
.nbRecords
= nMaxPossibleRecords
;
523 else if (m_aHeader
.nbRecords
> nMaxPossibleRecords
)
525 SAL_WARN("connectivity.drivers", "Parsing error: " << nMaxPossibleRecords
<<
526 " max possible records, but " << m_aHeader
.nbRecords
<< " claimed, truncating");
527 m_aHeader
.nbRecords
= std::max(nMaxPossibleRecords
, static_cast<size_t>(1));
533 // Create Memo-Filename (.DBT):
534 // nyi: Ugly for Unix and Mac!
536 if ( m_aHeader
.type
== FoxProMemo
|| m_aHeader
.type
== VisualFoxPro
|| m_aHeader
.type
== VisualFoxProAuto
) // foxpro uses another extension
537 aURL
.SetExtension(u
"fpt");
539 aURL
.SetExtension(u
"dbt");
541 // If the memo file isn't found, the data will be displayed anyhow.
542 // However, updates can't be done
543 // but the operation is executed
544 m_pMemoStream
= createStream_simpleError( aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
), StreamMode::READWRITE
| StreamMode::NOCREATE
| StreamMode::SHARE_DENYWRITE
);
545 if ( !m_pMemoStream
)
547 m_pMemoStream
= createStream_simpleError( aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
), StreamMode::READ
| StreamMode::NOCREATE
| StreamMode::SHARE_DENYNONE
);
554 m_pFileStream
->Seek(STREAM_SEEK_TO_BEGIN
);
557 // Buffersize dependent on the file size
558 m_pFileStream
->SetBufferSize(nFileSize
> 1000000 ? 32768 :
559 nFileSize
> 100000 ? 16384 :
560 nFileSize
> 10000 ? 4096 : 1024);
564 // set the buffer exactly to the length of a record
565 nFileSize
= m_pMemoStream
->TellEnd();
566 m_pMemoStream
->Seek(STREAM_SEEK_TO_BEGIN
);
568 // Buffersize dependent on the file size
569 m_pMemoStream
->SetBufferSize(nFileSize
> 1000000 ? 32768 :
570 nFileSize
> 100000 ? 16384 :
571 nFileSize
> 10000 ? 4096 :
572 m_aMemoHeader
.db_size
);
578 void ODbaseTable::ReadMemoHeader()
580 m_pMemoStream
->SetEndian(SvStreamEndian::LITTLE
);
581 m_pMemoStream
->RefreshBuffer(); // make sure that the header information is actually read again
582 m_pMemoStream
->Seek(0);
584 (*m_pMemoStream
).ReadUInt32( m_aMemoHeader
.db_next
);
585 switch (m_aHeader
.type
)
587 case dBaseIIIMemo
: // dBase III: fixed block size
589 // sometimes dBase3 is attached to dBase4 memo
590 m_pMemoStream
->Seek(20);
591 (*m_pMemoStream
).ReadUInt16( m_aMemoHeader
.db_size
);
592 if (m_aMemoHeader
.db_size
> 1 && m_aMemoHeader
.db_size
!= 512) // 1 is also for dBase 3
593 m_aMemoHeader
.db_typ
= MemodBaseIV
;
594 else if (m_aMemoHeader
.db_size
== 512)
596 // There are files using size specification, though they are dBase-files
598 m_pMemoStream
->Seek(m_aMemoHeader
.db_size
);
599 m_pMemoStream
->ReadBytes(sHeader
, 4);
601 if ((m_pMemoStream
->GetErrorCode() != ERRCODE_NONE
) || static_cast<sal_uInt8
>(sHeader
[0]) != 0xFF || static_cast<sal_uInt8
>(sHeader
[1]) != 0xFF || static_cast<sal_uInt8
>(sHeader
[2]) != 0x08)
602 m_aMemoHeader
.db_typ
= MemodBaseIII
;
604 m_aMemoHeader
.db_typ
= MemodBaseIV
;
608 m_aMemoHeader
.db_typ
= MemodBaseIII
;
609 m_aMemoHeader
.db_size
= 512;
613 case VisualFoxProAuto
:
615 m_aMemoHeader
.db_typ
= MemoFoxPro
;
616 m_pMemoStream
->Seek(6);
617 m_pMemoStream
->SetEndian(SvStreamEndian::BIG
);
618 (*m_pMemoStream
).ReadUInt16( m_aMemoHeader
.db_size
);
621 SAL_WARN( "connectivity.drivers", "ODbaseTable::ReadMemoHeader: unsupported memo type!" );
626 OUString
ODbaseTable::getEntry(file::OConnection
const * _pConnection
, std::u16string_view _sName
)
631 Reference
< XResultSet
> xDir
= _pConnection
->getDir()->getStaticResultSet();
632 Reference
< XRow
> xRow(xDir
,UNO_QUERY
);
639 sName
= xRow
->getString(1);
640 aURL
.SetSmartProtocol(INetProtocol::File
);
641 OUString sUrl
= _pConnection
->getURL() + "/" + sName
;
642 aURL
.SetSmartURL( sUrl
);
645 sExt
= aURL
.getExtension();
647 // name and extension have to coincide
648 if ( _pConnection
->matchesExtension( sExt
) )
650 sName
= sName
.replaceAt(sName
.getLength() - (sExt
.getLength() + 1), sExt
.getLength() + 1, OUString());
651 if ( sName
== _sName
)
653 Reference
< XContentAccess
> xContentAccess( xDir
, UNO_QUERY
);
654 sURL
= xContentAccess
->queryContentIdentifierString();
659 xDir
->beforeFirst(); // move back to before first record
661 catch(const Exception
&)
668 void ODbaseTable::refreshColumns()
670 ::osl::MutexGuard
aGuard( m_aMutex
);
672 ::std::vector
< OUString
> aVector
;
673 aVector
.reserve(m_aColumns
->size());
675 for (auto const& column
: *m_aColumns
)
676 aVector
.push_back(Reference
< XNamed
>(column
,UNO_QUERY_THROW
)->getName());
679 m_xColumns
->reFill(aVector
);
681 m_xColumns
= new ODbaseColumns(this,m_aMutex
,aVector
);
684 void ODbaseTable::refreshIndexes()
686 ::std::vector
< OUString
> aVector
;
687 if(m_pFileStream
&& (!m_xIndexes
|| m_xIndexes
->getCount() == 0))
690 aURL
.SetURL(getEntry(m_pConnection
,m_Name
));
692 aURL
.setExtension(u
"inf");
693 Config
aInfFile(aURL
.getFSysPath(FSysStyle::Detect
));
694 aInfFile
.SetGroup(dBASE_III_GROUP
);
695 sal_uInt16 nKeyCnt
= aInfFile
.GetKeyCount();
698 for (sal_uInt16 nKey
= 0; nKey
< nKeyCnt
; nKey
++)
700 // References the key an index-file?
701 aKeyName
= aInfFile
.GetKeyName( nKey
);
702 //...if yes, add the index list of the table
703 if (aKeyName
.startsWith("NDX"))
705 OString aIndexName
= aInfFile
.ReadKey(aKeyName
);
706 aURL
.setName(OStringToOUString(aIndexName
, m_eEncoding
));
709 Content
aCnt(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
710 if (aCnt
.isDocument())
712 aVector
.push_back(aURL
.getBase());
715 catch(const Exception
&) // an exception is thrown when no file exists
722 m_xIndexes
->reFill(aVector
);
724 m_xIndexes
= new ODbaseIndexes(this,m_aMutex
,aVector
);
728 void SAL_CALL
ODbaseTable::disposing()
730 OFileTable::disposing();
731 ::osl::MutexGuard
aGuard(m_aMutex
);
732 m_aColumns
= nullptr;
735 Sequence
< Type
> SAL_CALL
ODbaseTable::getTypes( )
737 Sequence
< Type
> aTypes
= OTable_TYPEDEF::getTypes();
738 std::vector
<Type
> aOwnTypes
;
739 aOwnTypes
.reserve(aTypes
.getLength());
741 const Type
* pBegin
= aTypes
.getConstArray();
742 const Type
* pEnd
= pBegin
+ aTypes
.getLength();
743 for(;pBegin
!= pEnd
;++pBegin
)
745 if(*pBegin
!= cppu::UnoType
<XKeysSupplier
>::get() &&
746 *pBegin
!= cppu::UnoType
<XDataDescriptorFactory
>::get())
748 aOwnTypes
.push_back(*pBegin
);
751 aOwnTypes
.push_back(cppu::UnoType
<css::lang::XUnoTunnel
>::get());
752 return Sequence
< Type
>(aOwnTypes
.data(), aOwnTypes
.size());
756 Any SAL_CALL
ODbaseTable::queryInterface( const Type
& rType
)
758 if( rType
== cppu::UnoType
<XKeysSupplier
>::get()||
759 rType
== cppu::UnoType
<XDataDescriptorFactory
>::get())
762 Any aRet
= OTable_TYPEDEF::queryInterface(rType
);
763 return aRet
.hasValue() ? aRet
: ::cppu::queryInterface(rType
,static_cast< css::lang::XUnoTunnel
*> (this));
767 Sequence
< sal_Int8
> ODbaseTable::getUnoTunnelId()
769 static ::cppu::OImplementationId implId
;
771 return implId
.getImplementationId();
774 // css::lang::XUnoTunnel
776 sal_Int64
ODbaseTable::getSomething( const Sequence
< sal_Int8
> & rId
)
778 return (isUnoTunnelId
<ODbaseTable
>(rId
))
779 ? reinterpret_cast< sal_Int64
>( this )
780 : ODbaseTable_BASE::getSomething(rId
);
783 bool ODbaseTable::fetchRow(OValueRefRow
& _rRow
, const OSQLColumns
& _rCols
, bool bRetrieveData
)
789 bool bIsCurRecordDeleted
= static_cast<char>(m_pBuffer
[0]) == '*';
791 // only read the bookmark
793 // Mark record as deleted
794 _rRow
->setDeleted(bIsCurRecordDeleted
);
795 *(*_rRow
)[0] = m_nFilePos
;
800 std::size_t nByteOffset
= 1;
802 OSQLColumns::const_iterator aIter
= _rCols
.begin();
803 OSQLColumns::const_iterator aEnd
= _rCols
.end();
804 const std::size_t nCount
= _rRow
->size();
805 for (std::size_t i
= 1; aIter
!= aEnd
&& nByteOffset
<= m_nBufferSize
&& i
< nCount
;++aIter
, i
++)
807 // Lengths depending on data type:
808 sal_Int32 nLen
= m_aPrecisions
[i
-1];
809 sal_Int32 nType
= m_aTypes
[i
-1];
813 case DataType::INTEGER
:
814 case DataType::DOUBLE
:
815 case DataType::TIMESTAMP
:
818 case DataType::LONGVARCHAR
:
819 case DataType::LONGVARBINARY
:
820 nLen
= m_aRealFieldLengths
[i
-1];
822 case DataType::DECIMAL
:
823 nLen
= SvDbaseConverter::ConvertPrecisionToDbase(nLen
,m_aScales
[i
-1]);
824 break; // the sign and the comma
826 case DataType::BINARY
:
827 case DataType::OTHER
:
832 // Is the variable bound?
833 if ( !(*_rRow
)[i
]->isBound() )
837 OSL_ENSURE( nByteOffset
<= m_nBufferSize
,"ByteOffset > m_nBufferSize!");
839 } // if ( !(_rRow->get())[i]->isBound() )
840 if ( ( nByteOffset
+ nLen
) > m_nBufferSize
)
841 break; // length doesn't match buffer size.
843 char *pData
= reinterpret_cast<char *>(m_pBuffer
.get() + nByteOffset
);
845 if (nType
== DataType::CHAR
|| nType
== DataType::VARCHAR
)
847 sal_Int32 nLastPos
= -1;
848 for (sal_Int32 k
= 0; k
< nLen
; ++k
)
851 // Record last non-empty position.
856 // Empty string. Skip it.
857 (*_rRow
)[i
]->setNull();
861 // Commit the string. Use intern() to ref-count it.
862 *(*_rRow
)[i
] = OUString::intern(pData
, static_cast<sal_Int32
>(nLastPos
+1), m_eEncoding
);
864 } // if (nType == DataType::CHAR || nType == DataType::VARCHAR)
865 else if ( DataType::TIMESTAMP
== nType
)
867 sal_Int32 nDate
= 0,nTime
= 0;
868 if (o3tl::make_unsigned(nLen
) < 8)
870 SAL_WARN("connectivity.drivers", "short TIMESTAMP");
873 memcpy(&nDate
, pData
, 4);
874 memcpy(&nTime
, pData
+ 4, 4);
875 if ( !nDate
&& !nTime
)
877 (*_rRow
)[i
]->setNull();
881 css::util::DateTime aDateTime
;
882 lcl_CalDate(nDate
,nTime
,aDateTime
);
883 *(*_rRow
)[i
] = aDateTime
;
886 else if ( DataType::INTEGER
== nType
)
888 sal_Int32 nValue
= 0;
889 if (o3tl::make_unsigned(nLen
) > sizeof(nValue
))
891 memcpy(&nValue
, pData
, nLen
);
892 *(*_rRow
)[i
] = nValue
;
894 else if ( DataType::DOUBLE
== nType
)
897 if (getBOOL((*aIter
)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))) // Currency is treated separately
899 sal_Int64 nValue
= 0;
900 if (o3tl::make_unsigned(nLen
) > sizeof(nValue
))
902 memcpy(&nValue
, pData
, nLen
);
904 if ( m_aScales
[i
-1] )
905 d
= (nValue
/ pow(10.0,static_cast<int>(m_aScales
[i
-1])));
907 d
= static_cast<double>(nValue
);
911 if (o3tl::make_unsigned(nLen
) > sizeof(d
))
913 memcpy(&d
, pData
, nLen
);
920 sal_Int32 nPos1
= -1, nPos2
= -1;
921 // If the string contains Nul-characters, then convert them to blanks!
922 for (sal_Int32 k
= 0; k
< nLen
; k
++)
924 if (pData
[k
] == '\0')
930 // first non-empty char position.
933 // last non-empty char position.
940 // Empty string. Skip it.
942 (*_rRow
)[i
]->setNull(); // no values -> done
946 OUString aStr
= OUString::intern(pData
+nPos1
, nPos2
-nPos1
+1, m_eEncoding
);
952 if (aStr
.getLength() != nLen
)
954 (*_rRow
)[i
]->setNull();
957 const sal_uInt16 nYear
= static_cast<sal_uInt16
>(aStr
.copy( 0, 4 ).toInt32());
958 const sal_uInt16 nMonth
= static_cast<sal_uInt16
>(aStr
.copy( 4, 2 ).toInt32());
959 const sal_uInt16 nDay
= static_cast<sal_uInt16
>(aStr
.copy( 6, 2 ).toInt32());
961 const css::util::Date
aDate(nDay
,nMonth
,nYear
);
962 *(*_rRow
)[i
] = aDate
;
965 case DataType::DECIMAL
:
966 *(*_rRow
)[i
] = ORowSetValue(aStr
);
975 case 'J': b
= true; break;
976 default: b
= false; break;
981 case DataType::LONGVARBINARY
:
982 case DataType::BINARY
:
983 case DataType::LONGVARCHAR
:
985 const tools::Long nBlockNo
= aStr
.toInt32(); // read blocknumber
986 if (nBlockNo
> 0 && m_pMemoStream
) // Read data from memo-file, only if
988 if ( !ReadMemo(nBlockNo
, (*_rRow
)[i
]->get()) )
992 (*_rRow
)[i
]->setNull();
995 SAL_WARN( "connectivity.drivers","Wrong type");
997 (*_rRow
)[i
]->setTypeKind(nType
);
1000 nByteOffset
+= nLen
;
1001 OSL_ENSURE( nByteOffset
<= m_nBufferSize
,"ByteOffset > m_nBufferSize!");
1007 void ODbaseTable::FileClose()
1009 ::osl::MutexGuard
aGuard(m_aMutex
);
1010 // if not everything has been written yet
1011 if (m_pMemoStream
&& m_pMemoStream
->IsWritable())
1012 m_pMemoStream
->Flush();
1014 m_pMemoStream
.reset();
1016 ODbaseTable_BASE::FileClose();
1019 bool ODbaseTable::CreateImpl()
1021 OSL_ENSURE(!m_pFileStream
, "SequenceError");
1023 if ( m_pConnection
->isCheckEnabled() && ::dbtools::convertName2SQLName(m_Name
,OUString()) != m_Name
)
1025 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1029 ::dbtools::throwGenericSQLException( sError
, *this );
1033 aURL
.SetSmartProtocol(INetProtocol::File
);
1034 OUString aName
= getEntry(m_pConnection
, m_Name
);
1037 OUString aIdent
= m_pConnection
->getContent()->getIdentifier()->getContentIdentifier();
1038 if ( aIdent
.lastIndexOf('/') != (aIdent
.getLength()-1) )
1045 if ( !m_pConnection
->matchesExtension( aURL
.getExtension() ) )
1046 aURL
.setExtension(m_pConnection
->getExtension());
1050 Content
aContent(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1051 if (aContent
.isDocument())
1053 // Only if the file exists with length > 0 raise an error
1054 std::unique_ptr
<SvStream
> pFileStream(createStream_simpleError( aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
), StreamMode::READ
));
1056 if (pFileStream
&& pFileStream
->TellEnd())
1060 catch(const Exception
&) // an exception is thrown when no file exists
1064 bool bMemoFile
= false;
1066 bool bOk
= CreateFile(aURL
, bMemoFile
);
1074 Content
aContent(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1075 aContent
.executeCommand( "delete", css::uno::Any( true ) );
1077 catch(const Exception
&) // an exception is thrown when no file exists
1085 OUString aExt
= aURL
.getExtension();
1086 aURL
.setExtension(u
"dbt"); // extension for memo file
1088 bool bMemoAlreadyExists
= false;
1091 Content
aMemo1Content(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1092 bMemoAlreadyExists
= aMemo1Content
.isDocument();
1094 catch(const Exception
&) // an exception is thrown when no file exists
1097 if (bMemoAlreadyExists
)
1099 aURL
.setExtension(aExt
); // kill dbf file
1102 Content
aMemoContent(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1103 aMemoContent
.executeCommand( "delete", css::uno::Any( true ) );
1105 catch(const Exception
&)
1107 css::uno::Any anyEx
= cppu::getCaughtException();
1108 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1109 STR_COULD_NOT_DELETE_FILE
,
1112 ::dbtools::throwGenericSQLException( sError
, *this, anyEx
);
1115 if (!CreateMemoFile(aURL
))
1117 aURL
.setExtension(aExt
); // kill dbf file
1120 Content
aMemoContent(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1121 aMemoContent
.executeCommand( "delete", css::uno::Any( true ) );
1123 catch(const ContentCreationException
&)
1125 css::uno::Any anyEx
= cppu::getCaughtException();
1126 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1127 STR_COULD_NOT_DELETE_FILE
,
1130 ::dbtools::throwGenericSQLException( sError
, *this, anyEx
);
1134 m_aHeader
.type
= dBaseIIIMemo
;
1137 m_aHeader
.type
= dBaseIII
;
1142 void ODbaseTable::throwInvalidColumnType(const char* pErrorId
, const OUString
& _sColumnName
)
1146 // we have to drop the file because it is corrupted now
1149 catch(const Exception
&)
1153 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1155 "$columnname$", _sColumnName
1157 ::dbtools::throwGenericSQLException( sError
, *this );
1160 // creates in principle dBase IV file format
1161 bool ODbaseTable::CreateFile(const INetURLObject
& aFile
, bool& bCreateMemo
)
1163 bCreateMemo
= false;
1164 Date
aDate( Date::SYSTEM
); // current date
1166 m_pFileStream
= createStream_simpleError( aFile
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
| StreamMode::TRUNC
);
1171 sal_uInt8 nDbaseType
= dBaseIII
;
1172 Reference
<XIndexAccess
> xColumns(getColumns(),UNO_QUERY
);
1173 Reference
<XPropertySet
> xCol
;
1174 const OUString sPropType
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
);
1178 const sal_Int32 nCount
= xColumns
->getCount();
1179 for(sal_Int32 i
=0;i
<nCount
;++i
)
1181 xColumns
->getByIndex(i
) >>= xCol
;
1182 OSL_ENSURE(xCol
.is(),"This should be a column!");
1184 switch (getINT32(xCol
->getPropertyValue(sPropType
)))
1186 case DataType::DOUBLE
:
1187 case DataType::INTEGER
:
1188 case DataType::TIMESTAMP
:
1189 case DataType::LONGVARBINARY
:
1190 nDbaseType
= VisualFoxPro
;
1191 i
= nCount
; // no more columns need to be checked
1193 } // switch (getINT32(xCol->getPropertyValue(sPropType)))
1196 catch ( const Exception
& )
1200 // we have to drop the file because it is corrupted now
1203 catch(const Exception
&) { }
1207 char aBuffer
[21] = {}; // write buffer
1209 m_pFileStream
->Seek(0);
1210 (*m_pFileStream
).WriteUChar( nDbaseType
); // dBase format
1211 (*m_pFileStream
).WriteUChar( aDate
.GetYearUnsigned() % 100 ); // current date
1214 (*m_pFileStream
).WriteUChar( aDate
.GetMonth() );
1215 (*m_pFileStream
).WriteUChar( aDate
.GetDay() );
1216 (*m_pFileStream
).WriteUInt32( 0 ); // number of data records
1217 (*m_pFileStream
).WriteUInt16( (m_xColumns
->getCount()+1) * 32 + 1 ); // header information,
1218 // pColumns contains always an additional column
1219 (*m_pFileStream
).WriteUInt16( 0 ); // record length will be determined later
1220 m_pFileStream
->WriteBytes(aBuffer
, 20);
1222 sal_uInt16 nRecLength
= 1; // Length 1 for deleted flag
1223 sal_Int32 nMaxFieldLength
= m_pConnection
->getMetaData()->getMaxColumnNameLength();
1225 const OUString sPropName
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
);
1226 const OUString sPropPrec
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION
);
1227 const OUString sPropScale
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
);
1231 const sal_Int32 nCount
= xColumns
->getCount();
1232 for(sal_Int32 i
=0;i
<nCount
;++i
)
1234 xColumns
->getByIndex(i
) >>= xCol
;
1235 OSL_ENSURE(xCol
.is(),"This should be a column!");
1239 xCol
->getPropertyValue(sPropName
) >>= aName
;
1242 if ( DBTypeConversion::convertUnicodeString( aName
, aCol
, m_eEncoding
) > nMaxFieldLength
)
1244 throwInvalidColumnType( STR_INVALID_COLUMN_NAME_LENGTH
, aName
);
1247 m_pFileStream
->WriteOString( aCol
);
1248 m_pFileStream
->WriteBytes(aBuffer
, 11 - aCol
.getLength());
1250 sal_Int32 nPrecision
= 0;
1251 xCol
->getPropertyValue(sPropPrec
) >>= nPrecision
;
1252 sal_Int32 nScale
= 0;
1253 xCol
->getPropertyValue(sPropScale
) >>= nScale
;
1255 bool bBinary
= false;
1257 switch (getINT32(xCol
->getPropertyValue(sPropType
)))
1259 case DataType::CHAR
:
1260 case DataType::VARCHAR
:
1263 case DataType::DOUBLE
:
1264 if (getBOOL(xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))) // Currency will be treated separately
1269 case DataType::INTEGER
:
1272 case DataType::TINYINT
:
1273 case DataType::SMALLINT
:
1274 case DataType::BIGINT
:
1275 case DataType::DECIMAL
:
1276 case DataType::NUMERIC
:
1277 case DataType::REAL
:
1278 cTyp
= 'N'; // only dBase 3 format
1280 case DataType::TIMESTAMP
:
1283 case DataType::DATE
:
1289 case DataType::LONGVARBINARY
:
1292 case DataType::LONGVARCHAR
:
1297 throwInvalidColumnType(STR_INVALID_COLUMN_TYPE
, aName
);
1301 (*m_pFileStream
).WriteChar( cTyp
);
1302 if ( nDbaseType
== VisualFoxPro
)
1303 (*m_pFileStream
).WriteUInt32( nRecLength
-1 );
1305 m_pFileStream
->WriteBytes(aBuffer
, 4);
1310 OSL_ENSURE(nPrecision
< 255, "ODbaseTable::Create: Column too long!");
1311 if (nPrecision
> 254)
1313 throwInvalidColumnType(STR_INVALID_COLUMN_PRECISION
, aName
);
1315 (*m_pFileStream
).WriteUChar( std::min(static_cast<unsigned>(nPrecision
), 255U) ); // field length
1316 nRecLength
= nRecLength
+ static_cast<sal_uInt16
>(std::min(static_cast<sal_uInt16
>(nPrecision
), sal_uInt16(255UL)));
1317 (*m_pFileStream
).WriteUChar( 0 ); // decimals
1321 OSL_ENSURE(nPrecision
>= nScale
,
1322 "ODbaseTable::Create: Field length must be larger than decimal places!");
1323 if (nPrecision
< nScale
)
1325 throwInvalidColumnType(STR_INVALID_PRECISION_SCALE
, aName
);
1327 if (getBOOL(xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))) // Currency will be treated separately
1329 (*m_pFileStream
).WriteUChar( 10 ); // standard length
1330 (*m_pFileStream
).WriteUChar( 4 );
1335 sal_Int32 nPrec
= SvDbaseConverter::ConvertPrecisionToDbase(nPrecision
,nScale
);
1337 (*m_pFileStream
).WriteUChar( nPrec
);
1338 (*m_pFileStream
).WriteUChar( nScale
);
1339 nRecLength
+= static_cast<sal_uInt16
>(nPrec
);
1343 (*m_pFileStream
).WriteUChar( 1 );
1344 (*m_pFileStream
).WriteUChar( 0 );
1348 (*m_pFileStream
).WriteUChar( 4 );
1349 (*m_pFileStream
).WriteUChar( 0 );
1356 (*m_pFileStream
).WriteUChar( 8 );
1357 (*m_pFileStream
).WriteUChar( 0 );
1362 (*m_pFileStream
).WriteUChar( 10 );
1363 (*m_pFileStream
).WriteUChar( 0 );
1369 throwInvalidColumnType(STR_INVALID_COLUMN_TYPE
, aName
);
1371 m_pFileStream
->WriteBytes(aBuffer
, 14);
1375 (*m_pFileStream
).WriteUChar( FIELD_DESCRIPTOR_TERMINATOR
); // end of header
1376 (*m_pFileStream
).WriteChar( char(DBF_EOL
) );
1377 m_pFileStream
->Seek(10);
1378 (*m_pFileStream
).WriteUInt16( nRecLength
); // set record length afterwards
1382 m_pFileStream
->Seek(0);
1383 if (nDbaseType
== VisualFoxPro
)
1384 (*m_pFileStream
).WriteUChar( FoxProMemo
);
1386 (*m_pFileStream
).WriteUChar( dBaseIIIMemo
);
1387 } // if (bCreateMemo)
1389 catch ( const Exception
& )
1393 // we have to drop the file because it is corrupted now
1396 catch(const Exception
&) { }
1403 // creates in principle dBase III file format
1404 bool ODbaseTable::CreateMemoFile(const INetURLObject
& aFile
)
1406 // filehandling macro for table creation
1407 m_pMemoStream
= createStream_simpleError( aFile
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),StreamMode::READWRITE
| StreamMode::SHARE_DENYWRITE
);
1412 m_pMemoStream
->SetStreamSize(512);
1414 m_pMemoStream
->Seek(0);
1415 (*m_pMemoStream
).WriteUInt32( 1 ); // pointer to the first free block
1417 m_pMemoStream
->Flush();
1418 m_pMemoStream
.reset();
1422 bool ODbaseTable::Drop_Static(const OUString
& _sUrl
, bool _bHasMemoFields
, OCollection
* _pIndexes
)
1427 bool bDropped
= ::utl::UCBContentHelper::Kill(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
1431 if (_bHasMemoFields
)
1432 { // delete the memo fields
1433 aURL
.setExtension(u
"dbt");
1434 bDropped
= ::utl::UCBContentHelper::Kill(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
));
1443 sal_Int32 i
= _pIndexes
->getCount();
1446 _pIndexes
->dropByIndex(--i
);
1449 catch(const SQLException
&)
1453 aURL
.setExtension(u
"inf");
1455 // as the inf file does not necessarily exist, we aren't allowed to use UCBContentHelper::Kill
1458 ::ucbhelper::Content
aDeleteContent( aURL
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
1459 aDeleteContent
.executeCommand( "delete", makeAny( true ) );
1461 catch(const Exception
&)
1463 // silently ignore this...
1470 bool ODbaseTable::DropImpl()
1475 refreshIndexes(); // look for indexes which must be deleted as well
1477 bool bDropped
= Drop_Static(getEntry(m_pConnection
,m_Name
),HasMemoFields(),m_xIndexes
.get());
1479 {// we couldn't drop the table so we have to reopen it
1482 m_xColumns
->refresh();
1488 bool ODbaseTable::InsertRow(OValueRefVector
& rRow
, const Reference
<XIndexAccess
>& _xCols
)
1490 // fill buffer with blanks
1494 memset(m_pBuffer
.get(), 0, m_aHeader
.recordLength
);
1497 // Copy new row completely:
1498 // ... and add at the end as new Record:
1499 std::size_t nTempPos
= m_nFilePos
;
1501 m_nFilePos
= static_cast<std::size_t>(m_aHeader
.nbRecords
) + 1;
1502 bool bInsertRow
= UpdateBuffer( rRow
, nullptr, _xCols
, true );
1505 std::size_t nFileSize
= 0, nMemoFileSize
= 0;
1507 nFileSize
= lcl_getFileSize(*m_pFileStream
);
1509 if (HasMemoFields() && m_pMemoStream
)
1511 m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
1512 nMemoFileSize
= m_pMemoStream
->Tell();
1517 m_pFileStream
->SetStreamSize(nFileSize
); // restore old size
1519 if (HasMemoFields() && m_pMemoStream
)
1520 m_pMemoStream
->SetStreamSize(nMemoFileSize
); // restore old size
1521 m_nFilePos
= nTempPos
; // restore file position
1525 (*m_pFileStream
).WriteChar( char(DBF_EOL
) ); // write EOL
1526 // raise number of datasets in the header:
1527 m_pFileStream
->Seek( 4 );
1528 (*m_pFileStream
).WriteUInt32( m_aHeader
.nbRecords
+ 1 );
1530 m_pFileStream
->Flush();
1532 // raise number if successfully
1533 m_aHeader
.nbRecords
++;
1534 *rRow
[0] = m_nFilePos
; // set bookmark
1535 m_nFilePos
= nTempPos
;
1539 m_nFilePos
= nTempPos
;
1545 bool ODbaseTable::UpdateRow(OValueRefVector
& rRow
, OValueRefRow
& pOrgRow
, const Reference
<XIndexAccess
>& _xCols
)
1547 // fill buffer with blanks
1551 // position on desired record:
1552 std::size_t nPos
= m_aHeader
.headerLength
+ static_cast<tools::Long
>(m_nFilePos
-1) * m_aHeader
.recordLength
;
1553 m_pFileStream
->Seek(nPos
);
1554 m_pFileStream
->ReadBytes(m_pBuffer
.get(), m_aHeader
.recordLength
);
1556 std::size_t nMemoFileSize( 0 );
1557 if (HasMemoFields() && m_pMemoStream
)
1559 m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
1560 nMemoFileSize
= m_pMemoStream
->Tell();
1562 if (!UpdateBuffer(rRow
, pOrgRow
, _xCols
, false) || !WriteBuffer())
1564 if (HasMemoFields() && m_pMemoStream
)
1565 m_pMemoStream
->SetStreamSize(nMemoFileSize
); // restore old size
1569 m_pFileStream
->Flush();
1575 bool ODbaseTable::DeleteRow(const OSQLColumns
& _rCols
)
1577 // Set the Delete-Flag (be it set or not):
1578 // Position on desired record:
1579 std::size_t nFilePos
= m_aHeader
.headerLength
+ static_cast<tools::Long
>(m_nFilePos
-1) * m_aHeader
.recordLength
;
1580 m_pFileStream
->Seek(nFilePos
);
1582 OValueRefRow aRow
= new OValueRefVector(_rCols
.size());
1584 if (!fetchRow(aRow
,_rCols
,true))
1587 Reference
<XPropertySet
> xCol
;
1589 ::comphelper::UStringMixEqual
aCase(isCaseSensitive());
1590 for (sal_Int32 i
= 0; i
< m_xColumns
->getCount(); i
++)
1592 Reference
<XPropertySet
> xIndex
= isUniqueByColumnName(i
);
1595 xCol
.set(m_xColumns
->getByIndex(i
), css::uno::UNO_QUERY
);
1596 OSL_ENSURE(xCol
.is(),"ODbaseTable::DeleteRow column is null!");
1599 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1601 Reference
<XUnoTunnel
> xTunnel(xIndex
,UNO_QUERY
);
1602 OSL_ENSURE(xTunnel
.is(),"No TunnelImplementation!");
1603 ODbaseIndex
* pIndex
= reinterpret_cast< ODbaseIndex
* >( xTunnel
->getSomething(ODbaseIndex::getUnoTunnelId()) );
1604 OSL_ENSURE(pIndex
,"ODbaseTable::DeleteRow: No Index returned!");
1606 OSQLColumns::const_iterator aIter
= std::find_if(_rCols
.begin(), _rCols
.end(),
1607 [&aCase
, &aColName
](const OSQLColumns::value_type
& rxCol
) {
1608 return aCase(getString(rxCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME
))), aColName
); });
1609 if (aIter
== _rCols
.end())
1612 auto nPos
= static_cast<sal_Int32
>(std::distance(_rCols
.begin(), aIter
)) + 1;
1613 pIndex
->Delete(m_nFilePos
,*(*aRow
)[nPos
]);
1618 m_pFileStream
->Seek(nFilePos
);
1619 (*m_pFileStream
).WriteUChar( '*' ); // mark the row in the table as deleted
1620 m_pFileStream
->Flush();
1624 Reference
<XPropertySet
> ODbaseTable::isUniqueByColumnName(sal_Int32 _nColumnPos
)
1628 if(m_xIndexes
->hasElements())
1630 Reference
<XPropertySet
> xCol
;
1631 m_xColumns
->getByIndex(_nColumnPos
) >>= xCol
;
1632 OSL_ENSURE(xCol
.is(),"ODbaseTable::isUniqueByColumnName column is null!");
1634 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= sColName
;
1636 Reference
<XPropertySet
> xIndex
;
1637 for(sal_Int32 i
=0;i
<m_xIndexes
->getCount();++i
)
1639 xIndex
.set(m_xIndexes
->getByIndex(i
), css::uno::UNO_QUERY
);
1640 if(xIndex
.is() && getBOOL(xIndex
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE
))))
1642 Reference
<XNameAccess
> xCols(Reference
<XColumnsSupplier
>(xIndex
,UNO_QUERY_THROW
)->getColumns());
1643 if(xCols
->hasByName(sColName
))
1649 return Reference
<XPropertySet
>();
1652 static double toDouble(const OString
& rString
)
1654 return ::rtl::math::stringToDouble( rString
, '.', ',' );
1658 bool ODbaseTable::UpdateBuffer(OValueRefVector
& rRow
, const OValueRefRow
& pOrgRow
, const Reference
<XIndexAccess
>& _xCols
, const bool bForceAllFields
)
1660 OSL_ENSURE(m_pBuffer
,"Buffer is NULL!");
1663 sal_Int32 nByteOffset
= 1;
1666 Reference
<XPropertySet
> xCol
;
1667 Reference
<XPropertySet
> xIndex
;
1669 const sal_Int32 nColumnCount
= m_xColumns
->getCount();
1670 std::vector
< Reference
<XPropertySet
> > aIndexedCols(nColumnCount
);
1672 ::comphelper::UStringMixEqual
aCase(isCaseSensitive());
1674 Reference
<XIndexAccess
> xColumns
= m_xColumns
;
1675 // first search a key that exist already in the table
1676 for (sal_Int32 i
= 0; i
< nColumnCount
; ++i
)
1679 if(_xCols
!= xColumns
)
1681 m_xColumns
->getByIndex(i
) >>= xCol
;
1682 OSL_ENSURE(xCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1683 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1685 for(nPos
= 0;nPos
<_xCols
->getCount();++nPos
)
1687 Reference
<XPropertySet
> xFindCol(
1688 _xCols
->getByIndex(nPos
), css::uno::UNO_QUERY
);
1689 OSL_ENSURE(xFindCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1690 if(aCase(getString(xFindCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
))),aColName
))
1693 if (nPos
>= _xCols
->getCount())
1698 xIndex
= isUniqueByColumnName(i
);
1699 aIndexedCols
[i
] = xIndex
;
1702 // first check if the value is different to the old one and when if it conform to the index
1703 if(pOrgRow
.is() && (rRow
[nPos
]->getValue().isNull() || rRow
[nPos
] == (*pOrgRow
)[nPos
]))
1707 Reference
<XUnoTunnel
> xTunnel(xIndex
,UNO_QUERY
);
1708 OSL_ENSURE(xTunnel
.is(),"No TunnelImplementation!");
1709 ODbaseIndex
* pIndex
= reinterpret_cast< ODbaseIndex
* >( xTunnel
->getSomething(ODbaseIndex::getUnoTunnelId()) );
1710 OSL_ENSURE(pIndex
,"ODbaseTable::UpdateBuffer: No Index returned!");
1712 if (pIndex
->Find(0,*rRow
[nPos
]))
1714 // There is no unique value
1715 if ( aColName
.isEmpty() )
1717 m_xColumns
->getByIndex(i
) >>= xCol
;
1718 OSL_ENSURE(xCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1719 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1721 } // if ( !aColName.getLength() )
1722 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1723 STR_DUPLICATE_VALUE_IN_COLUMN
1724 ,"$columnname$", aColName
1726 ::dbtools::throwGenericSQLException( sError
, *this );
1732 // when we are here there is no double key in the table
1734 for (sal_Int32 i
= 0; i
< nColumnCount
&& nByteOffset
<= m_nBufferSize
; ++i
)
1736 // Lengths for each data type:
1738 OSL_ENSURE(o3tl::make_unsigned(i
) < m_aPrecisions
.size(),"Illegal index!");
1740 sal_Int32 nType
= 0;
1741 sal_Int32 nScale
= 0;
1742 if ( o3tl::make_unsigned(i
) < m_aPrecisions
.size() )
1744 nLen
= m_aPrecisions
[i
];
1745 nType
= m_aTypes
[i
];
1746 nScale
= m_aScales
[i
];
1750 m_xColumns
->getByIndex(i
) >>= xCol
;
1753 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION
)) >>= nLen
;
1754 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
)) >>= nType
;
1755 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
)) >>= nScale
;
1759 bool bSetZero
= false;
1762 case DataType::INTEGER
:
1763 case DataType::DOUBLE
:
1764 case DataType::TIMESTAMP
:
1767 case DataType::LONGVARBINARY
:
1768 case DataType::DATE
:
1770 case DataType::LONGVARCHAR
:
1771 nLen
= m_aRealFieldLengths
[i
];
1773 case DataType::DECIMAL
:
1774 nLen
= SvDbaseConverter::ConvertPrecisionToDbase(nLen
,nScale
);
1775 break; // The sign and the comma
1782 if(_xCols
!= xColumns
)
1784 m_xColumns
->getByIndex(i
) >>= xCol
;
1785 OSL_ENSURE(xCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1786 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1787 for(nPos
= 0;nPos
<_xCols
->getCount();++nPos
)
1789 Reference
<XPropertySet
> xFindCol(
1790 _xCols
->getByIndex(nPos
), css::uno::UNO_QUERY
);
1791 if(aCase(getString(xFindCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
))),aColName
))
1794 if (nPos
>= _xCols
->getCount())
1796 nByteOffset
+= nLen
;
1802 ++nPos
; // the row values start at 1
1803 const ORowSetValue
&thisColVal
= rRow
[nPos
]->get();
1804 const bool thisColIsBound
= thisColVal
.isBound();
1805 const bool thisColIsNull
= !thisColIsBound
|| thisColVal
.isNull();
1806 // don't overwrite non-bound columns
1807 if ( ! (bForceAllFields
|| thisColIsBound
) )
1809 // No - don't overwrite this field, it has not changed.
1810 nByteOffset
+= nLen
;
1813 if (aIndexedCols
[i
].is())
1815 Reference
<XUnoTunnel
> xTunnel(aIndexedCols
[i
],UNO_QUERY
);
1816 OSL_ENSURE(xTunnel
.is(),"No TunnelImplementation!");
1817 ODbaseIndex
* pIndex
= reinterpret_cast< ODbaseIndex
* >( xTunnel
->getSomething(ODbaseIndex::getUnoTunnelId()) );
1818 OSL_ENSURE(pIndex
,"ODbaseTable::UpdateBuffer: No Index returned!");
1820 if (pOrgRow
.is() && !thisColIsNull
)
1821 pIndex
->Update(m_nFilePos
, *(*pOrgRow
)[nPos
], thisColVal
);
1823 pIndex
->Insert(m_nFilePos
, thisColVal
);
1826 char* pData
= reinterpret_cast<char *>(m_pBuffer
.get() + nByteOffset
);
1830 memset(pData
,0,nLen
); // Clear to NULL char ('\0')
1832 memset(pData
,' ',nLen
); // Clear to space/blank ('\0x20')
1833 nByteOffset
+= nLen
;
1834 OSL_ENSURE( nByteOffset
<= m_nBufferSize
,"ByteOffset > m_nBufferSize!");
1842 case DataType::TIMESTAMP
:
1844 sal_Int32 nJulianDate
= 0, nJulianTime
= 0;
1845 lcl_CalcJulDate(nJulianDate
,nJulianTime
, thisColVal
);
1846 // Exactly 8 bytes to copy:
1847 memcpy(pData
,&nJulianDate
,4);
1848 memcpy(pData
+4,&nJulianTime
,4);
1851 case DataType::DATE
:
1853 css::util::Date aDate
;
1854 if(thisColVal
.getTypeKind() == DataType::DOUBLE
)
1855 aDate
= ::dbtools::DBTypeConversion::toDate(thisColVal
.getDouble());
1858 char s
[sizeof("-327686553565535")];
1859 // reserve enough space for hypothetical max length
1862 "%04" SAL_PRIdINT32
"%02" SAL_PRIuUINT32
"%02" SAL_PRIuUINT32
,
1863 static_cast<sal_Int32
>(aDate
.Year
),
1864 static_cast<sal_uInt32
>(aDate
.Month
),
1865 static_cast<sal_uInt32
>(aDate
.Day
));
1867 // Exactly 8 bytes to copy (even if s could hypothetically be longer):
1870 case DataType::INTEGER
:
1872 sal_Int32 nValue
= thisColVal
;
1873 if (o3tl::make_unsigned(nLen
) > sizeof(nValue
))
1875 memcpy(pData
,&nValue
,nLen
);
1878 case DataType::DOUBLE
:
1880 const double d
= thisColVal
;
1881 m_xColumns
->getByIndex(i
) >>= xCol
;
1883 if (getBOOL(xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))) // Currency is treated separately
1885 sal_Int64 nValue
= 0;
1887 nValue
= static_cast<sal_Int64
>(d
* pow(10.0,static_cast<int>(m_aScales
[i
])));
1889 nValue
= static_cast<sal_Int64
>(d
);
1890 if (o3tl::make_unsigned(nLen
) > sizeof(nValue
))
1892 memcpy(pData
,&nValue
,nLen
);
1893 } // if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency is treated separately
1896 if (o3tl::make_unsigned(nLen
) > sizeof(d
))
1898 memcpy(pData
,&d
,nLen
);
1902 case DataType::DECIMAL
:
1904 memset(pData
,' ',nLen
); // Clear to NULL
1906 const double n
= thisColVal
;
1908 // one, because const_cast GetFormatPrecision on SvNumberFormat is not constant,
1909 // even though it really could and should be
1910 const OString
aDefaultValue( ::rtl::math::doubleToString( n
, rtl_math_StringFormat_F
, nScale
, '.', nullptr, 0));
1911 const sal_Int32 nValueLen
= aDefaultValue
.getLength();
1912 if ( nValueLen
<= nLen
)
1914 // Write value right-justified, padded with blanks to the left.
1915 memcpy(pData
+nLen
-nValueLen
,aDefaultValue
.getStr(),nValueLen
);
1916 // write the resulting double back
1917 *rRow
[nPos
] = toDouble(aDefaultValue
);
1921 m_xColumns
->getByIndex(i
) >>= xCol
;
1922 OSL_ENSURE(xCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1923 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1924 std::vector
< std::pair
<const char* , OUString
> > aStringToSubstitutes
1926 { "$columnname$", aColName
},
1927 { "$precision$", OUString::number(nLen
) },
1928 { "$scale$", OUString::number(nScale
) },
1929 { "$value$", OStringToOUString(aDefaultValue
,RTL_TEXTENCODING_UTF8
) }
1932 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1933 STR_INVALID_COLUMN_DECIMAL_VALUE
1934 ,aStringToSubstitutes
1936 ::dbtools::throwGenericSQLException( sError
, *this );
1940 *pData
= thisColVal
.getBool() ? 'T' : 'F';
1942 case DataType::LONGVARBINARY
:
1943 case DataType::LONGVARCHAR
:
1945 char cNext
= pData
[nLen
]; // Mark's scratch and replaced by 0
1946 pData
[nLen
] = '\0'; // This is because the buffer is always a sign of greater ...
1948 std::size_t nBlockNo
= strtol(pData
,nullptr,10); // Block number read
1950 // Next initial character restore again:
1951 pData
[nLen
] = cNext
;
1954 WriteMemo(thisColVal
, nBlockNo
);
1956 OString
aBlock(OString::number(nBlockNo
));
1957 //align aBlock at the right of a nLen sequence, fill to the left with '0'
1959 comphelper::string::padToLength(aStr
, nLen
- aBlock
.getLength(), '0');
1960 aStr
.append(aBlock
);
1963 memcpy(pData
, aStr
.getStr(), nLen
);
1967 memset(pData
,' ',nLen
); // Clear to NULL
1969 OUString
sStringToWrite( thisColVal
.getString() );
1971 // convert the string, using the connection's encoding
1974 DBTypeConversion::convertUnicodeStringToLength( sStringToWrite
, sEncoded
, nLen
, m_eEncoding
);
1975 memcpy( pData
, sEncoded
.getStr(), sEncoded
.getLength() );
1981 catch( const SQLException
& )
1985 catch ( const Exception
& )
1987 m_xColumns
->getByIndex(i
) >>= xCol
;
1988 OSL_ENSURE( xCol
.is(), "ODbaseTable::UpdateBuffer column is null!" );
1990 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1992 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1993 STR_INVALID_COLUMN_VALUE
,
1994 "$columnname$", aColName
1996 ::dbtools::throwGenericSQLException( sError
, *this );
1999 nByteOffset
+= nLen
;
2000 OSL_ENSURE( nByteOffset
<= m_nBufferSize
,"ByteOffset > m_nBufferSize!");
2006 void ODbaseTable::WriteMemo(const ORowSetValue
& aVariable
, std::size_t& rBlockNr
)
2008 // if the BlockNo 0 is given, the block will be appended at the end
2009 std::size_t nSize
= 0;
2011 css::uno::Sequence
<sal_Int8
> aValue
;
2012 sal_uInt8 nHeader
[4];
2013 const bool bBinary
= aVariable
.getTypeKind() == DataType::LONGVARBINARY
&& m_aMemoHeader
.db_typ
== MemoFoxPro
;
2016 aValue
= aVariable
.getSequence();
2017 nSize
= aValue
.getLength();
2021 nSize
= DBTypeConversion::convertUnicodeString( aVariable
.getString(), aStr
, m_eEncoding
);
2024 // append or overwrite
2025 bool bAppend
= rBlockNr
== 0;
2029 switch (m_aMemoHeader
.db_typ
)
2031 case MemodBaseIII
: // dBase III-Memofield, ends with 2 * Ctrl-Z
2032 bAppend
= nSize
> (512 - 2);
2035 case MemodBaseIV
: // dBase IV-Memofield with length
2038 m_pMemoStream
->Seek(rBlockNr
* m_aMemoHeader
.db_size
);
2039 m_pMemoStream
->SeekRel(4);
2040 m_pMemoStream
->ReadBytes(sHeader
, 4);
2042 std::size_t nOldSize
;
2043 if (m_aMemoHeader
.db_typ
== MemoFoxPro
)
2044 nOldSize
= ((static_cast<unsigned char>(sHeader
[0]) * 256 +
2045 static_cast<unsigned char>(sHeader
[1])) * 256 +
2046 static_cast<unsigned char>(sHeader
[2])) * 256 +
2047 static_cast<unsigned char>(sHeader
[3]);
2049 nOldSize
= ((static_cast<unsigned char>(sHeader
[3]) * 256 +
2050 static_cast<unsigned char>(sHeader
[2])) * 256 +
2051 static_cast<unsigned char>(sHeader
[1])) * 256 +
2052 static_cast<unsigned char>(sHeader
[0]) - 8;
2054 // fits the new length in the used blocks
2055 std::size_t nUsedBlocks
= ((nSize
+ 8) / m_aMemoHeader
.db_size
) + (((nSize
+ 8) % m_aMemoHeader
.db_size
> 0) ? 1 : 0),
2056 nOldUsedBlocks
= ((nOldSize
+ 8) / m_aMemoHeader
.db_size
) + (((nOldSize
+ 8) % m_aMemoHeader
.db_size
> 0) ? 1 : 0);
2057 bAppend
= nUsedBlocks
> nOldUsedBlocks
;
2064 sal_uInt64
const nStreamSize
= m_pMemoStream
->TellEnd();
2066 rBlockNr
= (nStreamSize
/ m_aMemoHeader
.db_size
) + ((nStreamSize
% m_aMemoHeader
.db_size
) > 0 ? 1 : 0);
2068 m_pMemoStream
->SetStreamSize(rBlockNr
* m_aMemoHeader
.db_size
);
2069 m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
2073 m_pMemoStream
->Seek(rBlockNr
* m_aMemoHeader
.db_size
);
2076 switch (m_aMemoHeader
.db_typ
)
2078 case MemodBaseIII
: // dBase III-Memofield, ends with Ctrl-Z
2080 const char cEOF
= char(DBF_EOL
);
2082 m_pMemoStream
->WriteBytes(aStr
.getStr(), aStr
.getLength());
2083 m_pMemoStream
->WriteChar( cEOF
).WriteChar( cEOF
);
2086 case MemodBaseIV
: // dBase IV-Memofield with length
2088 if ( MemodBaseIV
== m_aMemoHeader
.db_typ
)
2089 (*m_pMemoStream
).WriteUChar( 0xFF )
2091 .WriteUChar( 0x08 );
2093 (*m_pMemoStream
).WriteUChar( 0x00 )
2095 .WriteUChar( 0x00 );
2097 sal_uInt32 nWriteSize
= nSize
;
2098 if (m_aMemoHeader
.db_typ
== MemoFoxPro
)
2101 (*m_pMemoStream
).WriteUChar( 0x00 ); // Picture
2103 (*m_pMemoStream
).WriteUChar( 0x01 ); // Memo
2104 for (int i
= 4; i
> 0; nWriteSize
>>= 8)
2105 nHeader
[--i
] = static_cast<sal_uInt8
>(nWriteSize
% 256);
2109 (*m_pMemoStream
).WriteUChar( 0x00 );
2111 for (int i
= 0; i
< 4; nWriteSize
>>= 8)
2112 nHeader
[i
++] = static_cast<sal_uInt8
>(nWriteSize
% 256);
2115 m_pMemoStream
->WriteBytes(nHeader
, 4);
2117 m_pMemoStream
->WriteBytes(aValue
.getConstArray(), aValue
.getLength());
2119 m_pMemoStream
->WriteBytes(aStr
.getStr(), aStr
.getLength());
2120 m_pMemoStream
->Flush();
2125 // Write the new block number
2128 sal_uInt64
const nStreamSize
= m_pMemoStream
->TellEnd();
2129 m_aMemoHeader
.db_next
= (nStreamSize
/ m_aMemoHeader
.db_size
) + ((nStreamSize
% m_aMemoHeader
.db_size
) > 0 ? 1 : 0);
2131 // Write the new block number
2132 m_pMemoStream
->Seek(0);
2133 (*m_pMemoStream
).WriteUInt32( m_aMemoHeader
.db_next
);
2134 m_pMemoStream
->Flush();
2140 void SAL_CALL
ODbaseTable::alterColumnByName( const OUString
& colName
, const Reference
< XPropertySet
>& descriptor
)
2142 ::osl::MutexGuard
aGuard(m_aMutex
);
2143 checkDisposed(OTableDescriptor_BASE::rBHelper
.bDisposed
);
2146 Reference
<XDataDescriptorFactory
> xOldColumn
;
2147 m_xColumns
->getByName(colName
) >>= xOldColumn
;
2151 alterColumn(m_xColumns
->findColumn(colName
)-1,descriptor
,xOldColumn
);
2153 catch (const css::lang::IndexOutOfBoundsException
&)
2155 throw NoSuchElementException(colName
, *this);
2159 void SAL_CALL
ODbaseTable::alterColumnByIndex( sal_Int32 index
, const Reference
< XPropertySet
>& descriptor
)
2161 ::osl::MutexGuard
aGuard(m_aMutex
);
2162 checkDisposed(OTableDescriptor_BASE::rBHelper
.bDisposed
);
2164 if(index
< 0 || index
>= m_xColumns
->getCount())
2165 throw IndexOutOfBoundsException(OUString::number(index
),*this);
2167 Reference
<XDataDescriptorFactory
> xOldColumn
;
2168 m_xColumns
->getByIndex(index
) >>= xOldColumn
;
2169 alterColumn(index
,descriptor
,xOldColumn
);
2172 void ODbaseTable::alterColumn(sal_Int32 index
,
2173 const Reference
< XPropertySet
>& descriptor
,
2174 const Reference
< XDataDescriptorFactory
>& xOldColumn
)
2176 if(index
< 0 || index
>= m_xColumns
->getCount())
2177 throw IndexOutOfBoundsException(OUString::number(index
),*this);
2181 OSL_ENSURE(descriptor
.is(),"ODbaseTable::alterColumn: descriptor can not be null!");
2182 // creates a copy of the original column and copy all properties from descriptor in xCopyColumn
2183 Reference
<XPropertySet
> xCopyColumn
;
2185 xCopyColumn
= xOldColumn
->createDataDescriptor();
2187 xCopyColumn
= new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2189 ::comphelper::copyProperties(descriptor
,xCopyColumn
);
2191 // creates a temp file
2193 OUString sTempName
= createTempFile();
2195 rtl::Reference
<ODbaseTable
> pNewTable
= new ODbaseTable(m_pTables
,static_cast<ODbaseConnection
*>(m_pConnection
));
2196 Reference
<XPropertySet
> xHoldTable
= pNewTable
;
2197 pNewTable
->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
),makeAny(sTempName
));
2198 Reference
<XAppend
> xAppend(pNewTable
->getColumns(),UNO_QUERY
);
2199 OSL_ENSURE(xAppend
.is(),"ODbaseTable::alterColumn: No XAppend interface!");
2201 // copy the structure
2205 Reference
<XPropertySet
> xProp
;
2206 m_xColumns
->getByIndex(i
) >>= xProp
;
2207 Reference
<XDataDescriptorFactory
> xColumn(xProp
,UNO_QUERY
);
2208 Reference
<XPropertySet
> xCpy
;
2210 xCpy
= xColumn
->createDataDescriptor();
2212 xCpy
= new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2213 ::comphelper::copyProperties(xProp
,xCpy
);
2214 xAppend
->appendByDescriptor(xCpy
);
2216 ++i
; // now insert our new column
2217 xAppend
->appendByDescriptor(xCopyColumn
);
2219 for(;i
< m_xColumns
->getCount();++i
)
2221 Reference
<XPropertySet
> xProp
;
2222 m_xColumns
->getByIndex(i
) >>= xProp
;
2223 Reference
<XDataDescriptorFactory
> xColumn(xProp
,UNO_QUERY
);
2224 Reference
<XPropertySet
> xCpy
;
2226 xCpy
= xColumn
->createDataDescriptor();
2228 xCpy
= new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2229 ::comphelper::copyProperties(xProp
,xCpy
);
2230 xAppend
->appendByDescriptor(xCpy
);
2233 // construct the new table
2234 if(!pNewTable
->CreateImpl())
2236 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2237 STR_COLUMN_NOT_ALTERABLE
,
2238 "$columnname$", ::comphelper::getString(descriptor
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)))
2240 ::dbtools::throwGenericSQLException( sError
, *this );
2243 pNewTable
->construct();
2246 copyData(pNewTable
.get(),0);
2248 // now drop the old one
2249 if( DropImpl() ) // we don't want to delete the memo columns too
2253 // rename the new one to the old one
2254 pNewTable
->renameImpl(m_Name
);
2256 catch(const css::container::ElementExistException
&)
2258 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2259 STR_COULD_NOT_DELETE_FILE
,
2260 "$filename$", m_Name
2262 ::dbtools::throwGenericSQLException( sError
, *this );
2264 // release the temp file
2265 pNewTable
= nullptr;
2266 ::comphelper::disposeComponent(xHoldTable
);
2270 pNewTable
= nullptr;
2275 m_xColumns
->refresh();
2278 catch(const SQLException
&)
2282 catch(const Exception
&)
2284 TOOLS_WARN_EXCEPTION( "connectivity.drivers","");
2289 Reference
< XDatabaseMetaData
> ODbaseTable::getMetaData() const
2291 return getConnection()->getMetaData();
2294 void SAL_CALL
ODbaseTable::rename( const OUString
& newName
)
2296 ::osl::MutexGuard
aGuard(m_aMutex
);
2297 checkDisposed(OTableDescriptor_BASE::rBHelper
.bDisposed
);
2298 if(m_pTables
&& m_pTables
->hasByName(newName
))
2299 throw ElementExistException(newName
,*this);
2302 renameImpl(newName
);
2304 ODbaseTable_BASE::rename(newName
);
2308 m_xColumns
->refresh();
2312 void renameFile(file::OConnection
const * _pConnection
,std::u16string_view oldName
,
2313 const OUString
& newName
, std::u16string_view _sExtension
)
2315 OUString aName
= ODbaseTable::getEntry(_pConnection
,oldName
);
2318 OUString aIdent
= _pConnection
->getContent()->getIdentifier()->getContentIdentifier();
2319 if ( aIdent
.lastIndexOf('/') != (aIdent
.getLength()-1) )
2327 aURL
.setExtension( _sExtension
);
2328 OUString
sNewName(newName
+ "." + _sExtension
);
2332 Content
aContent(aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
2334 Sequence
< PropertyValue
> aProps( 1 );
2335 aProps
[0].Name
= "Title";
2336 aProps
[0].Handle
= -1; // n/a
2337 aProps
[0].Value
<<= sNewName
;
2338 Sequence
< Any
> aValues
;
2339 aContent
.executeCommand( "setPropertyValues",makeAny(aProps
) ) >>= aValues
;
2340 if(aValues
.hasElements() && aValues
[0].hasValue())
2341 throw Exception("setPropertyValues returned non-zero", nullptr);
2343 catch(const Exception
&)
2345 throw ElementExistException(newName
);
2350 void ODbaseTable::renameImpl( const OUString
& newName
)
2352 ::osl::MutexGuard
aGuard(m_aMutex
);
2357 renameFile(m_pConnection
,m_Name
,newName
,m_pConnection
->getExtension());
2358 if ( HasMemoFields() )
2359 { // delete the memo fields
2360 renameFile(m_pConnection
,m_Name
,newName
,u
"dbt");
2364 void ODbaseTable::addColumn(const Reference
< XPropertySet
>& _xNewColumn
)
2366 OUString sTempName
= createTempFile();
2368 rtl::Reference
xNewTable(new ODbaseTable(m_pTables
,static_cast<ODbaseConnection
*>(m_pConnection
)));
2369 xNewTable
->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
),makeAny(sTempName
));
2371 Reference
<XAppend
> xAppend(xNewTable
->getColumns(),UNO_QUERY
);
2372 bool bCase
= getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
2373 // copy the structure
2374 for(sal_Int32 i
=0;i
< m_xColumns
->getCount();++i
)
2376 Reference
<XPropertySet
> xProp
;
2377 m_xColumns
->getByIndex(i
) >>= xProp
;
2378 Reference
<XDataDescriptorFactory
> xColumn(xProp
,UNO_QUERY
);
2379 Reference
<XPropertySet
> xCpy
;
2381 xCpy
= xColumn
->createDataDescriptor();
2384 xCpy
= new OColumn(bCase
);
2385 ::comphelper::copyProperties(xProp
,xCpy
);
2388 xAppend
->appendByDescriptor(xCpy
);
2390 Reference
<XPropertySet
> xCpy
= new OColumn(bCase
);
2391 ::comphelper::copyProperties(_xNewColumn
,xCpy
);
2392 xAppend
->appendByDescriptor(xCpy
);
2395 // construct the new table
2396 if(!xNewTable
->CreateImpl())
2398 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2399 STR_COLUMN_NOT_ADDABLE
,
2400 "$columnname$", ::comphelper::getString(_xNewColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)))
2402 ::dbtools::throwGenericSQLException( sError
, *this );
2405 xNewTable
->construct();
2407 copyData(xNewTable
.get(),xNewTable
->m_xColumns
->getCount());
2408 // drop the old table
2411 xNewTable
->renameImpl(m_Name
);
2412 // release the temp file
2419 m_xColumns
->refresh();
2422 void ODbaseTable::dropColumn(sal_Int32 _nPos
)
2424 OUString sTempName
= createTempFile();
2426 rtl::Reference
xNewTable(new ODbaseTable(m_pTables
,static_cast<ODbaseConnection
*>(m_pConnection
)));
2427 xNewTable
->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
),makeAny(sTempName
));
2429 Reference
<XAppend
> xAppend(xNewTable
->getColumns(),UNO_QUERY
);
2430 bool bCase
= getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
2431 // copy the structure
2432 for(sal_Int32 i
=0;i
< m_xColumns
->getCount();++i
)
2436 Reference
<XPropertySet
> xProp
;
2437 m_xColumns
->getByIndex(i
) >>= xProp
;
2438 Reference
<XDataDescriptorFactory
> xColumn(xProp
,UNO_QUERY
);
2439 Reference
<XPropertySet
> xCpy
;
2441 xCpy
= xColumn
->createDataDescriptor();
2444 xCpy
= new OColumn(bCase
);
2445 ::comphelper::copyProperties(xProp
,xCpy
);
2447 xAppend
->appendByDescriptor(xCpy
);
2452 // construct the new table
2453 if(!xNewTable
->CreateImpl())
2455 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2456 STR_COLUMN_NOT_DROP
,
2457 "$position$", OUString::number(_nPos
)
2459 ::dbtools::throwGenericSQLException( sError
, *this );
2461 xNewTable
->construct();
2463 copyData(xNewTable
.get(),_nPos
);
2464 // drop the old table
2466 xNewTable
->renameImpl(m_Name
);
2467 // release the temp file
2475 OUString
ODbaseTable::createTempFile()
2477 OUString aIdent
= m_pConnection
->getContent()->getIdentifier()->getContentIdentifier();
2478 if ( aIdent
.lastIndexOf('/') != (aIdent
.getLength()-1) )
2481 OUString
sTempName(aIdent
);
2482 OUString
sExt("." + m_pConnection
->getExtension());
2483 OUString
sName(m_Name
);
2484 TempFile
aTempFile(sName
, true, &sExt
, &sTempName
);
2485 if(!aTempFile
.IsValid())
2486 getConnection()->throwGenericSQLException(STR_COULD_NOT_ALTER_TABLE
, *this);
2489 aURL
.SetSmartProtocol(INetProtocol::File
);
2490 aURL
.SetURL(aTempFile
.GetURL());
2492 OUString
sNewName(aURL
.getName().copy(0, aURL
.getName().getLength() - sExt
.getLength()));
2497 void ODbaseTable::copyData(ODbaseTable
* _pNewTable
,sal_Int32 _nPos
)
2499 sal_Int32 nPos
= _nPos
+ 1; // +1 because we always have the bookmark column as well
2500 OValueRefRow aRow
= new OValueRefVector(m_xColumns
->getCount());
2501 OValueRefRow aInsertRow
;
2504 aInsertRow
= new OValueRefVector(_pNewTable
->m_xColumns
->getCount());
2505 std::for_each(aInsertRow
->begin(),aInsertRow
->end(),TSetRefBound(true));
2510 // we only have to bind the values which we need to copy into the new table
2511 std::for_each(aRow
->begin(),aRow
->end(),TSetRefBound(true));
2512 if(_nPos
&& (_nPos
< static_cast<sal_Int32
>(aRow
->size())))
2513 (*aRow
)[nPos
]->setBound(false);
2517 OValueRefVector::const_iterator aIter
;
2518 for(sal_uInt32 nRowPos
= 0; nRowPos
< m_aHeader
.nbRecords
;++nRowPos
)
2520 bool bOk
= seekRow( IResultSetHelper::BOOKMARK
, nRowPos
+1, nCurPos
);
2523 bOk
= fetchRow( aRow
, *m_aColumns
, true);
2524 if ( bOk
&& !aRow
->isDeleted() ) // copy only not deleted rows
2526 // special handling when pos == 0 then we don't have to distinguish between the two rows
2529 aIter
= aRow
->begin()+1;
2530 sal_Int32 nCount
= 1;
2531 for(OValueRefVector::iterator aInsertIter
= aInsertRow
->begin()+1; aIter
!= aRow
->end() && aInsertIter
!= aInsertRow
->end();++aIter
,++nCount
)
2535 (*aInsertIter
)->setValue( (*aIter
)->getValue() );
2540 bOk
= _pNewTable
->InsertRow(*aInsertRow
,_pNewTable
->m_xColumns
);
2541 SAL_WARN_IF(!bOk
, "connectivity.drivers", "Row could not be inserted!");
2545 SAL_WARN_IF(!bOk
, "connectivity.drivers", "Row could not be fetched!");
2552 } // for(sal_uInt32 nRowPos = 0; nRowPos < m_aHeader.db_anz;++nRowPos)
2555 void ODbaseTable::throwInvalidDbaseFormat()
2560 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2561 STR_INVALID_DBASE_FILE
,
2562 "$filename$", getEntry(m_pConnection
,m_Name
)
2564 ::dbtools::throwGenericSQLException( sError
, *this );
2567 void ODbaseTable::refreshHeader()
2569 if ( m_aHeader
.nbRecords
== 0 )
2573 bool ODbaseTable::seekRow(IResultSetHelper::Movement eCursorPosition
, sal_Int32 nOffset
, sal_Int32
& nCurPos
)
2575 // prepare positioning:
2576 OSL_ENSURE(m_pFileStream
,"ODbaseTable::seekRow: FileStream is NULL!");
2578 sal_uInt32 nNumberOfRecords
= m_aHeader
.nbRecords
;
2579 sal_uInt32 nTempPos
= m_nFilePos
;
2580 m_nFilePos
= nCurPos
;
2582 switch(eCursorPosition
)
2584 case IResultSetHelper::NEXT
:
2587 case IResultSetHelper::PRIOR
:
2591 case IResultSetHelper::FIRST
:
2594 case IResultSetHelper::LAST
:
2595 m_nFilePos
= nNumberOfRecords
;
2597 case IResultSetHelper::RELATIVE1
:
2598 m_nFilePos
= (m_nFilePos
+ nOffset
< 0) ? 0
2599 : static_cast<sal_uInt32
>(m_nFilePos
+ nOffset
);
2601 case IResultSetHelper::ABSOLUTE1
:
2602 case IResultSetHelper::BOOKMARK
:
2603 m_nFilePos
= static_cast<sal_uInt32
>(nOffset
);
2607 if (m_nFilePos
> static_cast<sal_Int32
>(nNumberOfRecords
))
2608 m_nFilePos
= static_cast<sal_Int32
>(nNumberOfRecords
) + 1;
2610 if (m_nFilePos
== 0 || m_nFilePos
== static_cast<sal_Int32
>(nNumberOfRecords
) + 1)
2614 std::size_t nEntryLen
= m_aHeader
.recordLength
;
2616 OSL_ENSURE(m_nFilePos
>= 1,"SdbDBFCursor::FileFetchRow: invalid record position");
2617 std::size_t nPos
= m_aHeader
.headerLength
+ static_cast<std::size_t>(m_nFilePos
-1) * nEntryLen
;
2619 m_pFileStream
->Seek(nPos
);
2620 if (m_pFileStream
->GetError() != ERRCODE_NONE
)
2623 std::size_t nRead
= m_pFileStream
->ReadBytes(m_pBuffer
.get(), nEntryLen
);
2624 if (nRead
!= nEntryLen
)
2626 SAL_WARN("connectivity.drivers", "ODbaseTable::seekRow: short read!");
2629 if (m_pFileStream
->GetError() != ERRCODE_NONE
)
2635 switch(eCursorPosition
)
2637 case IResultSetHelper::PRIOR
:
2638 case IResultSetHelper::FIRST
:
2641 case IResultSetHelper::LAST
:
2642 case IResultSetHelper::NEXT
:
2643 case IResultSetHelper::ABSOLUTE1
:
2644 case IResultSetHelper::RELATIVE1
:
2646 m_nFilePos
= nNumberOfRecords
+ 1;
2647 else if (nOffset
< 0)
2650 case IResultSetHelper::BOOKMARK
:
2651 m_nFilePos
= nTempPos
; // last position
2656 nCurPos
= m_nFilePos
;
2660 bool ODbaseTable::ReadMemo(std::size_t nBlockNo
, ORowSetValue
& aVariable
)
2662 m_pMemoStream
->Seek(nBlockNo
* m_aMemoHeader
.db_size
);
2663 switch (m_aMemoHeader
.db_typ
)
2665 case MemodBaseIII
: // dBase III-Memofield, ends with Ctrl-Z
2667 const char cEOF
= char(DBF_EOL
);
2668 OStringBuffer aBStr
;
2669 static char aBuf
[514];
2670 aBuf
[512] = 0; // avoid random value
2671 bool bReady
= false;
2675 m_pMemoStream
->ReadBytes(&aBuf
, 512);
2678 while (aBuf
[i
] != cEOF
&& ++i
< 512)
2680 bReady
= aBuf
[i
] == cEOF
;
2685 } while (!bReady
&& !m_pMemoStream
->eof());
2687 aVariable
= OStringToOUString(aBStr
.makeStringAndClear(),
2692 case MemodBaseIV
: // dBase IV-Memofield with length
2694 bool bIsText
= true;
2696 m_pMemoStream
->ReadBytes(sHeader
, 4);
2697 // Foxpro stores text and binary data
2698 if (m_aMemoHeader
.db_typ
== MemoFoxPro
)
2700 bIsText
= sHeader
[3] != 0;
2702 else if (static_cast<sal_uInt8
>(sHeader
[0]) != 0xFF || static_cast<sal_uInt8
>(sHeader
[1]) != 0xFF || static_cast<sal_uInt8
>(sHeader
[2]) != 0x08)
2707 sal_uInt32
nLength(0);
2708 (*m_pMemoStream
).ReadUInt32( nLength
);
2710 if (m_aMemoHeader
.db_typ
== MemodBaseIV
)
2717 OStringBuffer
aBuffer(read_uInt8s_ToOString(*m_pMemoStream
, nLength
));
2718 //pad it out with ' ' to expected length on short read
2719 sal_Int32 nRequested
= sal::static_int_cast
<sal_Int32
>(nLength
);
2720 comphelper::string::padToLength(aBuffer
, nRequested
, ' ');
2721 aVariable
= OStringToOUString(aBuffer
.makeStringAndClear(), m_eEncoding
);
2725 css::uno::Sequence
< sal_Int8
> aData(nLength
);
2726 m_pMemoStream
->ReadBytes(aData
.getArray(), nLength
);
2735 bool ODbaseTable::AllocBuffer()
2737 sal_uInt16 nSize
= m_aHeader
.recordLength
;
2738 SAL_WARN_IF(nSize
== 0, "connectivity.drivers", "Size too small");
2740 if (m_nBufferSize
!= nSize
)
2745 // if there is no buffer available: allocate:
2746 if (!m_pBuffer
&& nSize
> 0)
2748 m_nBufferSize
= nSize
;
2749 m_pBuffer
.reset(new sal_uInt8
[m_nBufferSize
+1]);
2752 return m_pBuffer
!= nullptr;
2755 bool ODbaseTable::WriteBuffer()
2757 OSL_ENSURE(m_nFilePos
>= 1,"SdbDBFCursor::FileFetchRow: invalid record position");
2759 // position on desired record:
2760 std::size_t nPos
= m_aHeader
.headerLength
+ static_cast<tools::Long
>(m_nFilePos
-1) * m_aHeader
.recordLength
;
2761 m_pFileStream
->Seek(nPos
);
2762 return m_pFileStream
->WriteBytes(m_pBuffer
.get(), m_aHeader
.recordLength
) > 0;
2765 sal_Int32
ODbaseTable::getCurrentLastPos() const
2767 return m_aHeader
.nbRecords
;
2770 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */