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/sdbc/ColumnValue.hpp>
22 #include <com/sun/star/sdbc/DataType.hpp>
23 #include <com/sun/star/ucb/XContentAccess.hpp>
24 #include <com/sun/star/sdbc/XRow.hpp>
25 #include <svl/converter.hxx>
26 #include "dbase/DConnection.hxx"
27 #include "dbase/DColumns.hxx"
28 #include <osl/thread.h>
29 #include <tools/config.hxx>
30 #include "dbase/DIndex.hxx"
31 #include "dbase/DIndexes.hxx"
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/sequence.hxx>
34 #include <svl/zforlist.hxx>
35 #include <unotools/syslocale.hxx>
36 #include <rtl/math.hxx>
37 #include <stdio.h> //sprintf
38 #include <ucbhelper/content.hxx>
39 #include <comphelper/extract.hxx>
40 #include <connectivity/dbexception.hxx>
41 #include <connectivity/dbconversion.hxx>
42 #include <com/sun/star/lang/DisposedException.hpp>
43 #include <comphelper/property.hxx>
44 #include <comphelper/string.hxx>
45 #include <unotools/tempfile.hxx>
46 #include <unotools/ucbhelper.hxx>
47 #include <comphelper/types.hxx>
48 #include <cppuhelper/exc_hlp.hxx>
49 #include "connectivity/PColumn.hxx"
50 #include "connectivity/dbtools.hxx"
51 #include "connectivity/FValue.hxx"
52 #include "connectivity/dbconversion.hxx"
53 #include "resource/dbase_res.hrc"
54 #include <rtl/logfile.hxx>
55 #include <rtl/strbuf.hxx>
59 using namespace ::comphelper
;
60 using namespace connectivity
;
61 using namespace connectivity::sdbcx
;
62 using namespace connectivity::dbase
;
63 using namespace connectivity::file
;
64 using namespace ::ucbhelper
;
65 using namespace ::utl
;
66 using namespace ::cppu
;
67 using namespace ::dbtools
;
68 using namespace ::com::sun::star::uno
;
69 using namespace ::com::sun::star::ucb
;
70 using namespace ::com::sun::star::beans
;
71 using namespace ::com::sun::star::sdbcx
;
72 using namespace ::com::sun::star::sdbc
;
73 using namespace ::com::sun::star::container
;
74 using namespace ::com::sun::star::lang
;
75 using namespace ::com::sun::star::i18n
;
77 // stored as the Field Descriptor terminator
78 #define FIELD_DESCRIPTOR_TERMINATOR 0x0D
83 sal_Int32
lcl_getFileSize(SvStream
& _rStream
)
85 sal_Int32 nFileSize
= 0;
86 _rStream
.Seek(STREAM_SEEK_TO_END
);
90 nFileSize
= _rStream
.Tell();
91 if ( cEOL
== DBF_EOL
)
96 calculates the Julian date
98 void lcl_CalcJulDate(sal_Int32
& _nJulianDate
,sal_Int32
& _nJulianTime
,const com::sun::star::util::DateTime _aDateTime
)
100 com::sun::star::util::DateTime aDateTime
= _aDateTime
;
102 if (aDateTime
.Month
> 12)
105 sal_uInt16 delta
= _aDateTime
.Month
/ 12;
106 aDateTime
.Year
+= delta
;
107 aDateTime
.Month
-= delta
* 12;
111 _nJulianTime
= ((aDateTime
.Hours
*3600000)+(aDateTime
.Minutes
*60000)+(aDateTime
.Seconds
*1000)+(aDateTime
.NanoSeconds
/1000000));
112 /* conversion factors */
115 if ( aDateTime
.Month
<= 2 )
117 iy0
= aDateTime
.Year
- 1;
118 im0
= aDateTime
.Month
+ 12;
122 iy0
= aDateTime
.Year
;
123 im0
= aDateTime
.Month
;
125 sal_Int32 ia
= iy0
/ 100;
126 sal_Int32 ib
= 2 - ia
+ (ia
>> 2);
127 /* calculate julian date */
128 if ( aDateTime
.Year
<= 0 )
130 _nJulianDate
= (sal_Int32
) ((365.25 * iy0
) - 0.75)
131 + (sal_Int32
) (30.6001 * (im0
+ 1) )
132 + aDateTime
.Day
+ 1720994;
133 } // if ( _aDateTime.Year <= 0 )
136 _nJulianDate
= static_cast<sal_Int32
>( ((365.25 * iy0
)
137 + (sal_Int32
) (30.6001 * (im0
+ 1))
138 + aDateTime
.Day
+ 1720994));
140 double JD
= _nJulianDate
+ 0.5;
141 _nJulianDate
= (sal_Int32
)( JD
+ 0.5);
142 const double gyr
= aDateTime
.Year
+ (0.01 * aDateTime
.Month
) + (0.0001 * aDateTime
.Day
);
143 if ( gyr
>= 1582.1015 ) /* on or after 15 October 1582 */
148 calculates date time from the Julian Date
150 void lcl_CalDate(sal_Int32 _nJulianDate
,sal_Int32 _nJulianTime
,com::sun::star::util::DateTime
& _rDateTime
)
155 sal_Int32 ka
= _nJulianDate
;
156 if ( _nJulianDate
>= 2299161 )
158 ialp
= (sal_Int32
)( ((double) _nJulianDate
- 1867216.25 ) / ( 36524.25 ));
159 ka
= _nJulianDate
+ 1 + ialp
- ( ialp
>> 2 );
161 sal_Int32 kb
= ka
+ 1524;
162 sal_Int32 kc
= (sal_Int32
) ( ((double) kb
- 122.1 ) / 365.25 );
163 sal_Int32 kd
= (sal_Int32
) ((double) kc
* 365.25);
164 sal_Int32 ke
= (sal_Int32
) ((double) ( kb
- kd
) / 30.6001 );
165 _rDateTime
.Day
= static_cast<sal_uInt16
>(kb
- kd
- ((sal_Int32
) ( (double) ke
* 30.6001 )));
167 _rDateTime
.Month
= static_cast<sal_uInt16
>(ke
- 13);
169 _rDateTime
.Month
= static_cast<sal_uInt16
>(ke
- 1);
170 if ( (_rDateTime
.Month
== 2) && (_rDateTime
.Day
> 28) )
172 if ( (_rDateTime
.Month
== 2) && (_rDateTime
.Day
== 29) && (ke
== 3) )
173 _rDateTime
.Year
= static_cast<sal_uInt16
>(kc
- 4716);
174 else if ( _rDateTime
.Month
> 2 )
175 _rDateTime
.Year
= static_cast<sal_uInt16
>(kc
- 4716);
177 _rDateTime
.Year
= static_cast<sal_uInt16
>(kc
- 4715);
182 double d_s
= _nJulianTime
/ 1000;
183 double d_m
= d_s
/ 60;
184 double d_h
= d_m
/ 60;
185 _rDateTime
.Hours
= (sal_uInt16
) (d_h
);
186 _rDateTime
.Minutes
= (sal_uInt16
) d_m
;
187 _rDateTime
.Seconds
= static_cast<sal_uInt16
>(( d_m
- (double) _rDateTime
.Minutes
) * 60.0);
193 // -------------------------------------------------------------------------
194 void ODbaseTable::readHeader()
196 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::readHeader" );
197 OSL_ENSURE(m_pFileStream
,"No Stream available!");
200 m_pFileStream
->RefreshBuffer(); // Make sure, that the header information actually is read again
201 m_pFileStream
->Seek(STREAM_SEEK_TO_BEGIN
);
204 (*m_pFileStream
) >> nType
;
205 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
206 throwInvalidDbaseFormat();
208 m_pFileStream
->Read((char*)(&m_aHeader
.db_aedat
), 3*sizeof(sal_uInt8
));
209 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
210 throwInvalidDbaseFormat();
211 (*m_pFileStream
) >> m_aHeader
.db_anz
;
212 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
213 throwInvalidDbaseFormat();
214 (*m_pFileStream
) >> m_aHeader
.db_kopf
;
215 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
216 throwInvalidDbaseFormat();
217 (*m_pFileStream
) >> m_aHeader
.db_slng
;
218 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
219 throwInvalidDbaseFormat();
220 m_pFileStream
->Read((char*)(&m_aHeader
.db_frei
), 20*sizeof(sal_uInt8
));
221 if(ERRCODE_NONE
!= m_pFileStream
->GetErrorCode())
222 throwInvalidDbaseFormat();
224 if ( ( ( m_aHeader
.db_kopf
- 1 ) / 32 - 1 ) <= 0 ) // number of fields
227 throwInvalidDbaseFormat();
231 // Consistency check of the header:
232 m_aHeader
.db_typ
= (DBFType
)nType
;
233 switch (m_aHeader
.db_typ
)
239 case VisualFoxProAuto
:
245 m_pFileStream
->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN
);
246 if ( m_aHeader
.db_frei
[17] != 0x00
247 && !m_aHeader
.db_frei
[18] && !m_aHeader
.db_frei
[19] && getConnection()->isTextEncodingDefaulted() )
249 switch(m_aHeader
.db_frei
[17])
251 case 0x01: m_eEncoding
= RTL_TEXTENCODING_IBM_437
; break; // DOS USA code page 437
252 case 0x02: m_eEncoding
= RTL_TEXTENCODING_IBM_850
; break; // DOS Multilingual code page 850
253 case 0x03: m_eEncoding
= RTL_TEXTENCODING_MS_1252
; break; // Windows ANSI code page 1252
254 case 0x04: m_eEncoding
= RTL_TEXTENCODING_APPLE_ROMAN
; break; // Standard Macintosh
255 case 0x64: m_eEncoding
= RTL_TEXTENCODING_IBM_852
; break; // EE MS-DOS code page 852
256 case 0x65: m_eEncoding
= RTL_TEXTENCODING_IBM_865
; break; // Nordic MS-DOS code page 865
257 case 0x66: m_eEncoding
= RTL_TEXTENCODING_IBM_866
; break; // Russian MS-DOS code page 866
258 case 0x67: m_eEncoding
= RTL_TEXTENCODING_IBM_861
; break; // Icelandic MS-DOS
259 //case 0x68: m_eEncoding = ; break; // Kamenicky (Czech) MS-DOS
260 //case 0x69: m_eEncoding = ; break; // Mazovia (Polish) MS-DOS
261 case 0x6A: m_eEncoding
= RTL_TEXTENCODING_IBM_737
; break; // Greek MS-DOS (437G)
262 case 0x6B: m_eEncoding
= RTL_TEXTENCODING_IBM_857
; break; // Turkish MS-DOS
263 case 0x6C: m_eEncoding
= RTL_TEXTENCODING_IBM_863
; break; // MS-DOS, Canada
264 case 0x78: m_eEncoding
= RTL_TEXTENCODING_MS_950
; break; // Windows, Traditional Chinese
265 case 0x79: m_eEncoding
= RTL_TEXTENCODING_MS_949
; break; // Windows, Korean (Hangul)
266 case 0x7A: m_eEncoding
= RTL_TEXTENCODING_MS_936
; break; // Windows, Simplified Chinese
267 case 0x7B: m_eEncoding
= RTL_TEXTENCODING_MS_932
; break; // Windows, Japanese (Shift-jis)
268 case 0x7C: m_eEncoding
= RTL_TEXTENCODING_MS_874
; break; // Windows, Thai
269 case 0x7D: m_eEncoding
= RTL_TEXTENCODING_MS_1255
; break; // Windows, Hebrew
270 case 0x7E: m_eEncoding
= RTL_TEXTENCODING_MS_1256
; break; // Windows, Arabic
271 case 0x96: m_eEncoding
= RTL_TEXTENCODING_APPLE_CYRILLIC
; break; // Russian Macintosh
272 case 0x97: m_eEncoding
= RTL_TEXTENCODING_APPLE_CENTEURO
; break; // Eastern European Macintosh
273 case 0x98: m_eEncoding
= RTL_TEXTENCODING_APPLE_GREEK
; break; // Greek Macintosh
274 case 0xC8: m_eEncoding
= RTL_TEXTENCODING_MS_1250
; break; // Windows EE code page 1250
275 case 0xC9: m_eEncoding
= RTL_TEXTENCODING_MS_1251
; break; // Russian Windows
276 case 0xCA: m_eEncoding
= RTL_TEXTENCODING_MS_1254
; break; // Turkish Windows
277 case 0xCB: m_eEncoding
= RTL_TEXTENCODING_MS_1253
; break; // Greek Windows
278 case 0xCC: m_eEncoding
= RTL_TEXTENCODING_MS_1257
; break; // Windows, Baltic
281 m_eEncoding
= RTL_TEXTENCODING_IBM_850
;
287 m_pFileStream
->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN
);
291 throwInvalidDbaseFormat();
296 // -------------------------------------------------------------------------
297 void ODbaseTable::fillColumns()
299 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::fillColumns" );
300 m_pFileStream
->Seek(STREAM_SEEK_TO_BEGIN
);
301 m_pFileStream
->Seek(32L);
304 m_aColumns
= new OSQLColumns();
306 m_aColumns
->get().clear();
309 m_aPrecisions
.clear();
313 const sal_Int32 nFieldCount
= (m_aHeader
.db_kopf
- 1) / 32 - 1;
314 OSL_ENSURE(nFieldCount
,"No columns in table!");
316 m_aColumns
->get().reserve(nFieldCount
);
317 m_aTypes
.reserve(nFieldCount
);
318 m_aPrecisions
.reserve(nFieldCount
);
319 m_aScales
.reserve(nFieldCount
);
321 String aStrFieldName
;
322 aStrFieldName
.AssignAscii("Column");
324 const sal_Bool bCase
= getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
325 const bool bFoxPro
= m_aHeader
.db_typ
== VisualFoxPro
|| m_aHeader
.db_typ
== VisualFoxProAuto
|| m_aHeader
.db_typ
== FoxProMemo
;
328 for (; i
< nFieldCount
; i
++)
330 DBFColumn aDBFColumn
;
331 m_pFileStream
->Read((char*)&aDBFColumn
, sizeof(aDBFColumn
));
332 if ( FIELD_DESCRIPTOR_TERMINATOR
== aDBFColumn
.db_fnm
[0] ) // 0x0D stored as the Field Descriptor terminator.
335 sal_Bool bIsRowVersion
= bFoxPro
&& ( aDBFColumn
.db_frei2
[0] & 0x01 ) == 0x01;
336 const String
aColumnName((const char *)aDBFColumn
.db_fnm
,m_eEncoding
);
338 m_aRealFieldLengths
.push_back(aDBFColumn
.db_flng
);
339 sal_Int32 nPrecision
= aDBFColumn
.db_flng
;
341 sal_Bool bIsCurrency
= sal_False
;
344 cType
[0] = aDBFColumn
.db_typ
;
346 aTypeName
= OUString::createFromAscii(cType
);
347 OSL_TRACE("column type: %c",aDBFColumn
.db_typ
);
349 switch (aDBFColumn
.db_typ
)
352 eType
= DataType::VARCHAR
;
353 aTypeName
= "VARCHAR";
357 aTypeName
= "DECIMAL";
358 if ( aDBFColumn
.db_typ
== 'N' )
359 aTypeName
= "NUMERIC";
360 eType
= DataType::DECIMAL
;
362 // for numeric fields two characters more are written, than the precision of the column description predescribes,
363 // to keep room for the possible sign and the comma. This has to be considered...
364 nPrecision
= SvDbaseConverter::ConvertPrecisionToOdbc(nPrecision
,aDBFColumn
.db_dez
);
365 // This is not true for older versions ....
368 eType
= DataType::BIT
;
369 aTypeName
= "BOOLEAN";
372 bIsCurrency
= sal_True
;
373 eType
= DataType::DOUBLE
;
374 aTypeName
= "DOUBLE";
377 eType
= DataType::DATE
;
381 eType
= DataType::TIMESTAMP
;
382 aTypeName
= "TIMESTAMP";
385 eType
= DataType::INTEGER
;
386 aTypeName
= "INTEGER";
389 if ( bFoxPro
&& ( aDBFColumn
.db_frei2
[0] & 0x04 ) == 0x04 )
391 eType
= DataType::LONGVARBINARY
;
392 aTypeName
= "LONGVARBINARY";
396 aTypeName
= "LONGVARCHAR";
397 eType
= DataType::LONGVARCHAR
;
399 nPrecision
= 2147483647;
402 aTypeName
= "LONGVARBINARY";
403 eType
= DataType::LONGVARBINARY
;
404 nPrecision
= 2147483647;
408 if ( m_aHeader
.db_typ
== VisualFoxPro
|| m_aHeader
.db_typ
== VisualFoxProAuto
)
410 aTypeName
= "DOUBLE";
411 eType
= DataType::DOUBLE
;
415 aTypeName
= "LONGVARBINARY";
416 eType
= DataType::LONGVARBINARY
;
417 nPrecision
= 2147483647;
421 eType
= DataType::OTHER
;
424 m_aTypes
.push_back(eType
);
425 m_aPrecisions
.push_back(nPrecision
);
426 m_aScales
.push_back(aDBFColumn
.db_dez
);
428 Reference
< XPropertySet
> xCol
= new sdbcx::OColumn(aColumnName
,
432 ColumnValue::NULLABLE
,
440 m_CatalogName
, getSchema(), getName());
441 m_aColumns
->get().push_back(xCol
);
442 } // for (; i < nFieldCount; i++)
443 OSL_ENSURE(i
,"No columns in table!");
445 // -------------------------------------------------------------------------
446 ODbaseTable::ODbaseTable(sdbcx::OCollection
* _pTables
,ODbaseConnection
* _pConnection
)
447 :ODbaseTable_BASE(_pTables
,_pConnection
)
449 ,m_bWriteableMemo(sal_False
)
451 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::ODbaseTable" );
452 // initialize the header
453 m_aHeader
.db_typ
= dBaseIII
;
454 m_aHeader
.db_anz
= 0;
455 m_aHeader
.db_kopf
= 0;
456 m_aHeader
.db_slng
= 0;
457 m_eEncoding
= getConnection()->getTextEncoding();
459 // -------------------------------------------------------------------------
460 ODbaseTable::ODbaseTable(sdbcx::OCollection
* _pTables
,ODbaseConnection
* _pConnection
,
461 const OUString
& _Name
,
462 const OUString
& _Type
,
463 const OUString
& _Description
,
464 const OUString
& _SchemaName
,
465 const OUString
& _CatalogName
466 ) : ODbaseTable_BASE(_pTables
,_pConnection
,_Name
,
472 ,m_bWriteableMemo(sal_False
)
474 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::ODbaseTable" );
475 m_eEncoding
= getConnection()->getTextEncoding();
478 // -----------------------------------------------------------------------------
479 void ODbaseTable::construct()
481 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::construct" );
482 // initialize the header
483 m_aHeader
.db_typ
= dBaseIII
;
484 m_aHeader
.db_anz
= 0;
485 m_aHeader
.db_kopf
= 0;
486 m_aHeader
.db_slng
= 0;
487 m_aMemoHeader
.db_size
= 0;
489 String
sFileName(getEntry(m_pConnection
,m_Name
));
492 aURL
.SetURL(sFileName
);
494 OSL_ENSURE( m_pConnection
->matchesExtension( aURL
.getExtension() ),
495 "ODbaseTable::ODbaseTable: invalid extension!");
496 // getEntry is expected to ensure the corect file name
498 m_pFileStream
= createStream_simpleError( sFileName
, STREAM_READWRITE
| STREAM_NOCREATE
| STREAM_SHARE_DENYWRITE
);
499 m_bWriteable
= ( m_pFileStream
!= NULL
);
501 if ( !m_pFileStream
)
503 m_bWriteable
= sal_False
;
504 m_pFileStream
= createStream_simpleError( sFileName
, STREAM_READ
| STREAM_NOCREATE
| STREAM_SHARE_DENYNONE
);
512 // Create Memo-Filename (.DBT):
513 // nyi: Ugly for Unix and Mac!
515 if ( m_aHeader
.db_typ
== FoxProMemo
|| VisualFoxPro
== m_aHeader
.db_typ
|| VisualFoxProAuto
== m_aHeader
.db_typ
) // foxpro uses another extension
516 aURL
.SetExtension("fpt");
518 aURL
.SetExtension("dbt");
520 // If the memo file isn't found, the data will be displayed anyhow.
521 // However, updates can't be done
522 // but the operation is executed
523 m_pMemoStream
= createStream_simpleError( aURL
.GetMainURL(INetURLObject::NO_DECODE
), STREAM_READWRITE
| STREAM_NOCREATE
| STREAM_SHARE_DENYWRITE
);
524 if ( !m_pMemoStream
)
526 m_bWriteableMemo
= sal_False
;
527 m_pMemoStream
= createStream_simpleError( aURL
.GetMainURL(INetURLObject::NO_DECODE
), STREAM_READ
| STREAM_NOCREATE
| STREAM_SHARE_DENYNONE
);
534 sal_uInt32 nFileSize
= lcl_getFileSize(*m_pFileStream
);
535 m_pFileStream
->Seek(STREAM_SEEK_TO_BEGIN
);
536 if ( m_aHeader
.db_anz
== 0 && ((nFileSize
-m_aHeader
.db_kopf
)/m_aHeader
.db_slng
) > 0) // seems to be empty or someone wrote bullshit into the dbase file
537 m_aHeader
.db_anz
= ((nFileSize
-m_aHeader
.db_kopf
)/m_aHeader
.db_slng
);
539 // Buffersize dependent on the file size
540 m_pFileStream
->SetBufferSize(nFileSize
> 1000000 ? 32768 :
541 nFileSize
> 100000 ? 16384 :
542 nFileSize
> 10000 ? 4096 : 1024);
546 // set the buffer extactly to the length of a record
547 m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
548 nFileSize
= m_pMemoStream
->Tell();
549 m_pMemoStream
->Seek(STREAM_SEEK_TO_BEGIN
);
551 // Buffersize dependent on the file size
552 m_pMemoStream
->SetBufferSize(nFileSize
> 1000000 ? 32768 :
553 nFileSize
> 100000 ? 16384 :
554 nFileSize
> 10000 ? 4096 :
555 m_aMemoHeader
.db_size
);
561 //------------------------------------------------------------------
562 sal_Bool
ODbaseTable::ReadMemoHeader()
564 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::ReadMemoHeader" );
565 m_pMemoStream
->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN
);
566 m_pMemoStream
->RefreshBuffer(); // make sure that the header information is actually read again
567 m_pMemoStream
->Seek(0L);
569 (*m_pMemoStream
) >> m_aMemoHeader
.db_next
;
570 switch (m_aHeader
.db_typ
)
572 case dBaseIIIMemo
: // dBase III: fixed block size
574 // sometimes dBase3 is attached to dBase4 memo
575 m_pMemoStream
->Seek(20L);
576 (*m_pMemoStream
) >> m_aMemoHeader
.db_size
;
577 if (m_aMemoHeader
.db_size
> 1 && m_aMemoHeader
.db_size
!= 512) // 1 is also for dBase 3
578 m_aMemoHeader
.db_typ
= MemodBaseIV
;
579 else if (m_aMemoHeader
.db_size
> 1 && m_aMemoHeader
.db_size
== 512)
581 // There are files using size specification, though they are dBase-files
583 m_pMemoStream
->Seek(m_aMemoHeader
.db_size
);
584 m_pMemoStream
->Read(sHeader
,4);
586 if ((m_pMemoStream
->GetErrorCode() != ERRCODE_NONE
) || ((sal_uInt8
)sHeader
[0]) != 0xFF || ((sal_uInt8
)sHeader
[1]) != 0xFF || ((sal_uInt8
)sHeader
[2]) != 0x08)
587 m_aMemoHeader
.db_typ
= MemodBaseIII
;
589 m_aMemoHeader
.db_typ
= MemodBaseIV
;
593 m_aMemoHeader
.db_typ
= MemodBaseIII
;
594 m_aMemoHeader
.db_size
= 512;
598 case VisualFoxProAuto
:
600 m_aMemoHeader
.db_typ
= MemoFoxPro
;
601 m_pMemoStream
->Seek(6L);
602 m_pMemoStream
->SetNumberFormatInt(NUMBERFORMAT_INT_BIGENDIAN
);
603 (*m_pMemoStream
) >> m_aMemoHeader
.db_size
;
606 OSL_FAIL( "ODbaseTable::ReadMemoHeader: unsupported memo type!" );
611 // -------------------------------------------------------------------------
612 String
ODbaseTable::getEntry(OConnection
* _pConnection
,const OUString
& _sName
)
614 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getEntry" );
618 Reference
< XResultSet
> xDir
= _pConnection
->getDir()->getStaticResultSet();
619 Reference
< XRow
> xRow(xDir
,UNO_QUERY
);
623 static const OUString
s_sSeparator("/");
627 sName
= xRow
->getString(1);
628 aURL
.SetSmartProtocol(INET_PROT_FILE
);
629 String sUrl
= _pConnection
->getURL() + s_sSeparator
+ sName
;
630 aURL
.SetSmartURL( sUrl
);
633 sExt
= aURL
.getExtension();
635 // name and extension have to coincide
636 if ( _pConnection
->matchesExtension( sExt
) )
638 sName
= sName
.replaceAt(sName
.getLength()-(sExt
.getLength()+1),sExt
.getLength()+1,OUString());
639 if ( sName
== _sName
)
641 Reference
< XContentAccess
> xContentAccess( xDir
, UNO_QUERY
);
642 sURL
= xContentAccess
->queryContentIdentifierString();
647 xDir
->beforeFirst(); // move back to before first record
649 catch(const Exception
&)
655 // -------------------------------------------------------------------------
656 void ODbaseTable::refreshColumns()
658 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::refreshColumns" );
659 ::osl::MutexGuard
aGuard( m_aMutex
);
661 TStringVector aVector
;
662 aVector
.reserve(m_aColumns
->get().size());
664 for(OSQLColumns::Vector::const_iterator aIter
= m_aColumns
->get().begin();aIter
!= m_aColumns
->get().end();++aIter
)
665 aVector
.push_back(Reference
< XNamed
>(*aIter
,UNO_QUERY
)->getName());
668 m_pColumns
->reFill(aVector
);
670 m_pColumns
= new ODbaseColumns(this,m_aMutex
,aVector
);
672 // -------------------------------------------------------------------------
673 void ODbaseTable::refreshIndexes()
675 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::refreshIndexes" );
676 TStringVector aVector
;
677 if(m_pFileStream
&& (!m_pIndexes
|| m_pIndexes
->getCount() == 0))
680 aURL
.SetURL(getEntry(m_pConnection
,m_Name
));
682 aURL
.setExtension("inf");
683 Config
aInfFile(aURL
.getFSysPath(INetURLObject::FSYS_DETECT
));
684 aInfFile
.SetGroup(dBASE_III_GROUP
);
685 sal_uInt16 nKeyCnt
= aInfFile
.GetKeyCount();
688 for (sal_uInt16 nKey
= 0; nKey
< nKeyCnt
; nKey
++)
690 // Refences the key an index-file?
691 aKeyName
= aInfFile
.GetKeyName( nKey
);
692 //...if yes, add the index list of the table
693 if (aKeyName
.copy(0,3).equalsL(RTL_CONSTASCII_STRINGPARAM("NDX")))
695 OString aIndexName
= aInfFile
.ReadKey(aKeyName
);
696 aURL
.setName(OStringToOUString(aIndexName
, m_eEncoding
));
699 Content
aCnt(aURL
.GetMainURL(INetURLObject::NO_DECODE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
700 if (aCnt
.isDocument())
702 aVector
.push_back(aURL
.getBase());
705 catch(const Exception
&) // an exception is thrown when no file exists
712 m_pIndexes
->reFill(aVector
);
714 m_pIndexes
= new ODbaseIndexes(this,m_aMutex
,aVector
);
717 // -------------------------------------------------------------------------
718 void SAL_CALL
ODbaseTable::disposing(void)
720 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::disposing" );
721 OFileTable::disposing();
722 ::osl::MutexGuard
aGuard(m_aMutex
);
725 // -------------------------------------------------------------------------
726 Sequence
< Type
> SAL_CALL
ODbaseTable::getTypes( ) throw(RuntimeException
)
728 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getTypes" );
729 Sequence
< Type
> aTypes
= OTable_TYPEDEF::getTypes();
730 ::std::vector
<Type
> aOwnTypes
;
731 aOwnTypes
.reserve(aTypes
.getLength());
733 const Type
* pBegin
= aTypes
.getConstArray();
734 const Type
* pEnd
= pBegin
+ aTypes
.getLength();
735 for(;pBegin
!= pEnd
;++pBegin
)
737 if(!(*pBegin
== ::getCppuType((const Reference
<XKeysSupplier
>*)0) ||
738 *pBegin
== ::getCppuType((const Reference
<XDataDescriptorFactory
>*)0)))
740 aOwnTypes
.push_back(*pBegin
);
743 aOwnTypes
.push_back(::getCppuType( (const Reference
< ::com::sun::star::lang::XUnoTunnel
> *)0 ));
744 Type
*pTypes
= aOwnTypes
.empty() ? 0 : &aOwnTypes
[0];
745 return Sequence
< Type
>(pTypes
, aOwnTypes
.size());
748 // -------------------------------------------------------------------------
749 Any SAL_CALL
ODbaseTable::queryInterface( const Type
& rType
) throw(RuntimeException
)
751 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::queryInterface" );
752 if( rType
== ::getCppuType((const Reference
<XKeysSupplier
>*)0) ||
753 rType
== ::getCppuType((const Reference
<XDataDescriptorFactory
>*)0))
756 Any aRet
= OTable_TYPEDEF::queryInterface(rType
);
757 return aRet
.hasValue() ? aRet
: ::cppu::queryInterface(rType
,static_cast< ::com::sun::star::lang::XUnoTunnel
*> (this));
760 //--------------------------------------------------------------------------
761 Sequence
< sal_Int8
> ODbaseTable::getUnoTunnelImplementationId()
763 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getUnoTunnelImplementationId" );
764 static ::cppu::OImplementationId
* pId
= 0;
767 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
770 static ::cppu::OImplementationId aId
;
774 return pId
->getImplementationId();
777 // com::sun::star::lang::XUnoTunnel
778 //------------------------------------------------------------------
779 sal_Int64
ODbaseTable::getSomething( const Sequence
< sal_Int8
> & rId
) throw (RuntimeException
)
781 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getSomething" );
782 return (rId
.getLength() == 16 && 0 == memcmp(getUnoTunnelImplementationId().getConstArray(), rId
.getConstArray(), 16 ) )
783 ? reinterpret_cast< sal_Int64
>( this )
784 : ODbaseTable_BASE::getSomething(rId
);
786 //------------------------------------------------------------------
787 sal_Bool
ODbaseTable::fetchRow(OValueRefRow
& _rRow
,const OSQLColumns
& _rCols
, sal_Bool _bUseTableDefs
,sal_Bool bRetrieveData
)
789 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::fetchRow" );
791 bool bIsCurRecordDeleted
= (char)m_pBuffer
[0] == '*';
793 // only read the bookmark
795 // Mark record as deleted
796 _rRow
->setDeleted(bIsCurRecordDeleted
);
797 *(_rRow
->get())[0] = m_nFilePos
;
802 sal_Size nByteOffset
= 1;
804 OSQLColumns::Vector::const_iterator aIter
= _rCols
.get().begin();
805 OSQLColumns::Vector::const_iterator aEnd
= _rCols
.get().end();
806 const sal_Size nCount
= _rRow
->get().size();
807 for (sal_Size i
= 1; aIter
!= aEnd
&& nByteOffset
<= m_nBufferSize
&& i
< nCount
;++aIter
, i
++)
809 // Lengths depending on data type:
814 nLen
= m_aPrecisions
[i
-1];
815 nType
= m_aTypes
[i
-1];
819 (*aIter
)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION
)) >>= nLen
;
820 (*aIter
)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
)) >>= nType
;
824 case DataType::INTEGER
:
825 case DataType::DOUBLE
:
826 case DataType::TIMESTAMP
:
829 case DataType::LONGVARCHAR
:
830 case DataType::LONGVARBINARY
:
831 nLen
= m_aRealFieldLengths
[i
-1];
833 case DataType::DECIMAL
:
835 nLen
= SvDbaseConverter::ConvertPrecisionToDbase(nLen
,m_aScales
[i
-1]);
837 nLen
= SvDbaseConverter::ConvertPrecisionToDbase(nLen
,getINT32((*aIter
)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
))));
838 break; // the sign and the comma
840 case DataType::BINARY
:
841 case DataType::OTHER
:
846 // Is the variable bound?
847 if ( !(_rRow
->get())[i
]->isBound() )
851 OSL_ENSURE( nByteOffset
<= m_nBufferSize
,"ByteOffset > m_nBufferSize!");
853 } // if ( !(_rRow->get())[i]->isBound() )
854 if ( ( nByteOffset
+ nLen
) > m_nBufferSize
)
855 break; // length doesn't match buffer size.
857 char *pData
= (char *) (m_pBuffer
+ nByteOffset
);
859 if (nType
== DataType::CHAR
|| nType
== DataType::VARCHAR
)
861 sal_Int32 nLastPos
= -1;
862 for (sal_Int32 k
= 0; k
< nLen
; ++k
)
865 // Record last non-empty position.
870 // Empty string. Skip it.
871 (_rRow
->get())[i
]->setNull();
875 // Commit the string. Use intern() to ref-count it.
876 *(_rRow
->get())[i
] = OUString::intern(pData
, static_cast<sal_Int32
>(nLastPos
+1), m_eEncoding
);
878 } // if (nType == DataType::CHAR || nType == DataType::VARCHAR)
879 else if ( DataType::TIMESTAMP
== nType
)
881 sal_Int32 nDate
= 0,nTime
= 0;
882 memcpy(&nDate
, pData
, 4);
883 memcpy(&nTime
, pData
+ 4, 4);
884 if ( !nDate
&& !nTime
)
886 (_rRow
->get())[i
]->setNull();
890 ::com::sun::star::util::DateTime aDateTime
;
891 lcl_CalDate(nDate
,nTime
,aDateTime
);
892 *(_rRow
->get())[i
] = aDateTime
;
895 else if ( DataType::INTEGER
== nType
)
897 sal_Int32 nValue
= 0;
898 memcpy(&nValue
, pData
, nLen
);
899 *(_rRow
->get())[i
] = nValue
;
901 else if ( DataType::DOUBLE
== nType
)
904 if (getBOOL((*aIter
)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))) // Currency is treated separately
906 sal_Int64 nValue
= 0;
907 memcpy(&nValue
, pData
, nLen
);
909 if ( m_aScales
[i
-1] )
910 d
= (double)(nValue
/ pow(10.0,(int)m_aScales
[i
-1]));
912 d
= (double)(nValue
);
916 memcpy(&d
, pData
, nLen
);
919 *(_rRow
->get())[i
] = d
;
923 sal_Int32 nPos1
= -1, nPos2
= -1;
924 // If the string contains Nul-characters, then convert them to blanks!
925 for (sal_Int32 k
= 0; k
< nLen
; k
++)
927 if (pData
[k
] == '\0')
933 // first non-empty char position.
936 // last non-empty char position.
943 // Empty string. Skip it.
945 (_rRow
->get())[i
]->setNull(); // no values -> done
949 OUString aStr
= OUString::intern(pData
+nPos1
, nPos2
-nPos1
+1, m_eEncoding
);
955 if (aStr
.getLength() != nLen
)
957 (_rRow
->get())[i
]->setNull();
960 const sal_uInt16 nYear
= (sal_uInt16
)aStr
.copy( 0, 4 ).toInt32();
961 const sal_uInt16 nMonth
= (sal_uInt16
)aStr
.copy( 4, 2 ).toInt32();
962 const sal_uInt16 nDay
= (sal_uInt16
)aStr
.copy( 6, 2 ).toInt32();
964 const ::com::sun::star::util::Date
aDate(nDay
,nMonth
,nYear
);
965 *(_rRow
->get())[i
] = aDate
;
968 case DataType::DECIMAL
:
969 *(_rRow
->get())[i
] = ORowSetValue(aStr
);
974 switch (* ((const char *)pData
))
978 case 'J': b
= sal_True
; break;
979 default: b
= sal_False
; break;
981 *(_rRow
->get())[i
] = b
;
984 case DataType::LONGVARBINARY
:
985 case DataType::BINARY
:
986 case DataType::LONGVARCHAR
:
988 const long nBlockNo
= aStr
.toInt32(); // read blocknumber
989 if (nBlockNo
> 0 && m_pMemoStream
) // Read data from memo-file, only if
991 if ( !ReadMemo(nBlockNo
, (_rRow
->get())[i
]->get()) )
995 (_rRow
->get())[i
]->setNull();
998 OSL_FAIL("Falscher Type");
1000 (_rRow
->get())[i
]->setTypeKind(nType
);
1003 nByteOffset
+= nLen
;
1004 OSL_ENSURE( nByteOffset
<= m_nBufferSize
,"ByteOffset > m_nBufferSize!");
1008 //------------------------------------------------------------------
1009 // -------------------------------------------------------------------------
1010 void ODbaseTable::FileClose()
1012 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::FileClose" );
1013 ::osl::MutexGuard
aGuard(m_aMutex
);
1014 // if not everything has been written yet
1015 if (m_pMemoStream
&& m_pMemoStream
->IsWritable())
1016 m_pMemoStream
->Flush();
1018 delete m_pMemoStream
;
1019 m_pMemoStream
= NULL
;
1021 ODbaseTable_BASE::FileClose();
1023 // -------------------------------------------------------------------------
1024 sal_Bool
ODbaseTable::CreateImpl()
1026 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::CreateImpl" );
1027 OSL_ENSURE(!m_pFileStream
, "SequenceError");
1029 if ( m_pConnection
->isCheckEnabled() && ::dbtools::convertName2SQLName(m_Name
,OUString()) != m_Name
)
1031 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1035 ::dbtools::throwGenericSQLException( sError
, *this );
1039 aURL
.SetSmartProtocol(INET_PROT_FILE
);
1040 String aName
= getEntry(m_pConnection
,m_Name
);
1043 OUString aIdent
= m_pConnection
->getContent()->getIdentifier()->getContentIdentifier();
1044 if ( aIdent
.lastIndexOf('/') != (aIdent
.getLength()-1) )
1047 aName
= aIdent
.getStr();
1051 if ( !m_pConnection
->matchesExtension( aURL
.getExtension() ) )
1052 aURL
.setExtension(m_pConnection
->getExtension());
1056 Content
aContent(aURL
.GetMainURL(INetURLObject::NO_DECODE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1057 if (aContent
.isDocument())
1059 // Only if the file exists with length > 0 raise an error
1060 SvStream
* pFileStream
= createStream_simpleError( aURL
.GetMainURL(INetURLObject::NO_DECODE
),STREAM_READ
);
1062 if (pFileStream
&& pFileStream
->Seek(STREAM_SEEK_TO_END
))
1069 catch(const Exception
&) // an exception is thrown when no file exists
1073 sal_Bool bMemoFile
= sal_False
;
1075 sal_Bool bOk
= CreateFile(aURL
, bMemoFile
);
1083 Content
aContent(aURL
.GetMainURL(INetURLObject::NO_DECODE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1084 aContent
.executeCommand( "delete",bool2any( sal_True
) );
1086 catch(const Exception
&) // an exception is thrown when no file exists
1094 String aExt
= aURL
.getExtension();
1095 aURL
.setExtension("dbt"); // extension for memo file
1096 Content
aMemo1Content(aURL
.GetMainURL(INetURLObject::NO_DECODE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1098 sal_Bool bMemoAlreadyExists
= sal_False
;
1101 bMemoAlreadyExists
= aMemo1Content
.isDocument();
1103 catch(const Exception
&) // an exception is thrown when no file exists
1106 if (bMemoAlreadyExists
)
1108 aURL
.setExtension(aExt
); // kill dbf file
1111 Content
aMemoContent(aURL
.GetMainURL(INetURLObject::NO_DECODE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1112 aMemoContent
.executeCommand( "delete",bool2any( sal_True
) );
1114 catch(const Exception
&)
1117 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1118 STR_COULD_NOT_DELETE_FILE
,
1121 ::dbtools::throwGenericSQLException( sError
, *this );
1124 if (!CreateMemoFile(aURL
))
1126 aURL
.setExtension(aExt
); // kill dbf file
1127 Content
aMemoContent(aURL
.GetMainURL(INetURLObject::NO_DECODE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
1128 aMemoContent
.executeCommand( "delete",bool2any( sal_True
) );
1131 m_aHeader
.db_typ
= dBaseIIIMemo
;
1134 m_aHeader
.db_typ
= dBaseIII
;
1138 // -----------------------------------------------------------------------------
1139 void ODbaseTable::throwInvalidColumnType(const sal_uInt16 _nErrorId
,const OUString
& _sColumnName
)
1141 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::throwInvalidColumnType" );
1144 // we have to drop the file because it is corrupted now
1147 catch(const Exception
&)
1151 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1153 "$columnname$", _sColumnName
1155 ::dbtools::throwGenericSQLException( sError
, *this );
1157 //------------------------------------------------------------------
1158 // creates in principle dBase IV file format
1159 sal_Bool
ODbaseTable::CreateFile(const INetURLObject
& aFile
, sal_Bool
& bCreateMemo
)
1161 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::CreateFile" );
1162 bCreateMemo
= sal_False
;
1163 Date
aDate( Date::SYSTEM
); // current date
1165 m_pFileStream
= createStream_simpleError( aFile
.GetMainURL(INetURLObject::NO_DECODE
),STREAM_READWRITE
| STREAM_SHARE_DENYWRITE
| STREAM_TRUNC
);
1170 sal_uInt8 nDbaseType
= dBaseIII
;
1171 Reference
<XIndexAccess
> xColumns(getColumns(),UNO_QUERY
);
1172 Reference
<XPropertySet
> xCol
;
1173 const OUString sPropType
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
);
1177 const sal_Int32 nCount
= xColumns
->getCount();
1178 for(sal_Int32 i
=0;i
<nCount
;++i
)
1180 xColumns
->getByIndex(i
) >>= xCol
;
1181 OSL_ENSURE(xCol
.is(),"This should be a column!");
1183 switch (getINT32(xCol
->getPropertyValue(sPropType
)))
1185 case DataType::DOUBLE
:
1186 case DataType::INTEGER
:
1187 case DataType::TIMESTAMP
:
1188 case DataType::LONGVARBINARY
:
1189 nDbaseType
= VisualFoxPro
;
1190 i
= nCount
; // no more columns need to be checked
1192 } // switch (getINT32(xCol->getPropertyValue(sPropType)))
1195 catch ( const Exception
& e
)
1201 // we have to drop the file because it is corrupted now
1204 catch(const Exception
&) { }
1208 char aBuffer
[21]; // write buffer
1209 memset(aBuffer
,0,sizeof(aBuffer
));
1211 m_pFileStream
->Seek(0L);
1212 (*m_pFileStream
) << (sal_uInt8
) nDbaseType
; // dBase format
1213 (*m_pFileStream
) << (sal_uInt8
) (aDate
.GetYear() % 100); // current date
1216 (*m_pFileStream
) << (sal_uInt8
) aDate
.GetMonth();
1217 (*m_pFileStream
) << (sal_uInt8
) aDate
.GetDay();
1218 (*m_pFileStream
) << (sal_uInt32
)0; // number of data records
1219 (*m_pFileStream
) << (sal_uInt16
)((m_pColumns
->getCount()+1) * 32 + 1); // header information,
1220 // pColumns contains always an additional column
1221 (*m_pFileStream
) << (sal_uInt16
) 0; // record length will be determined later
1222 m_pFileStream
->Write(aBuffer
, 20);
1224 sal_uInt16 nRecLength
= 1; // Length 1 for deleted flag
1225 sal_Int32 nMaxFieldLength
= m_pConnection
->getMetaData()->getMaxColumnNameLength();
1227 const OUString sPropName
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
);
1228 const OUString sPropPrec
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION
);
1229 const OUString sPropScale
= OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
);
1233 const sal_Int32 nCount
= xColumns
->getCount();
1234 for(sal_Int32 i
=0;i
<nCount
;++i
)
1236 xColumns
->getByIndex(i
) >>= xCol
;
1237 OSL_ENSURE(xCol
.is(),"This should be a column!");
1241 xCol
->getPropertyValue(sPropName
) >>= aName
;
1244 if ( DBTypeConversion::convertUnicodeString( aName
, aCol
, m_eEncoding
) > nMaxFieldLength
)
1246 throwInvalidColumnType( STR_INVALID_COLUMN_NAME_LENGTH
, aName
);
1249 (*m_pFileStream
) << aCol
.getStr();
1250 m_pFileStream
->Write(aBuffer
, 11 - aCol
.getLength());
1252 sal_Int32 nPrecision
= 0;
1253 xCol
->getPropertyValue(sPropPrec
) >>= nPrecision
;
1254 sal_Int32 nScale
= 0;
1255 xCol
->getPropertyValue(sPropScale
) >>= nScale
;
1257 bool bBinary
= false;
1259 switch (getINT32(xCol
->getPropertyValue(sPropType
)))
1261 case DataType::CHAR
:
1262 case DataType::VARCHAR
:
1265 case DataType::DOUBLE
:
1266 if (getBOOL(xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))) // Currency will be treated separately
1271 case DataType::INTEGER
:
1274 case DataType::TINYINT
:
1275 case DataType::SMALLINT
:
1276 case DataType::BIGINT
:
1277 case DataType::DECIMAL
:
1278 case DataType::NUMERIC
:
1279 case DataType::REAL
:
1280 cTyp
= 'N'; // only dBase 3 format
1282 case DataType::TIMESTAMP
:
1285 case DataType::DATE
:
1291 case DataType::LONGVARBINARY
:
1294 case DataType::LONGVARCHAR
:
1299 throwInvalidColumnType(STR_INVALID_COLUMN_TYPE
, aName
);
1303 (*m_pFileStream
) << cTyp
;
1304 if ( nDbaseType
== VisualFoxPro
)
1305 (*m_pFileStream
) << sal_uInt32(nRecLength
-1);
1307 m_pFileStream
->Write(aBuffer
, 4);
1312 OSL_ENSURE(nPrecision
< 255, "ODbaseTable::Create: Column zu lang!");
1313 if (nPrecision
> 254)
1315 throwInvalidColumnType(STR_INVALID_COLUMN_PRECISION
, aName
);
1317 (*m_pFileStream
) << (sal_uInt8
) std::min((unsigned)nPrecision
, 255U); // field length
1318 nRecLength
= nRecLength
+ (sal_uInt16
)::std::min((sal_uInt16
)nPrecision
, (sal_uInt16
)255UL);
1319 (*m_pFileStream
) << (sal_uInt8
)0; // decimals
1323 OSL_ENSURE(nPrecision
>= nScale
,
1324 "ODbaseTable::Create: Feldlaenge muss groesser Nachkommastellen sein!");
1325 if (nPrecision
< nScale
)
1327 throwInvalidColumnType(STR_INVALID_PRECISION_SCALE
, aName
);
1329 if (getBOOL(xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))) // Currency will be treated separately
1331 (*m_pFileStream
) << (sal_uInt8
)10; // standard length
1332 (*m_pFileStream
) << (sal_uInt8
)4;
1337 sal_Int32 nPrec
= SvDbaseConverter::ConvertPrecisionToDbase(nPrecision
,nScale
);
1339 (*m_pFileStream
) << (sal_uInt8
)( nPrec
);
1340 (*m_pFileStream
) << (sal_uInt8
)nScale
;
1341 nRecLength
+= (sal_uInt16
)nPrec
;
1345 (*m_pFileStream
) << (sal_uInt8
)1;
1346 (*m_pFileStream
) << (sal_uInt8
)0;
1350 (*m_pFileStream
) << (sal_uInt8
)4;
1351 (*m_pFileStream
) << (sal_uInt8
)0;
1358 (*m_pFileStream
) << (sal_uInt8
)8;
1359 (*m_pFileStream
) << (sal_uInt8
)0;
1363 bCreateMemo
= sal_True
;
1364 (*m_pFileStream
) << (sal_uInt8
)10;
1365 (*m_pFileStream
) << (sal_uInt8
)0;
1371 throwInvalidColumnType(STR_INVALID_COLUMN_TYPE
, aName
);
1373 m_pFileStream
->Write(aBuffer
, 14);
1377 (*m_pFileStream
) << (sal_uInt8
)FIELD_DESCRIPTOR_TERMINATOR
; // end of header
1378 (*m_pFileStream
) << (char)DBF_EOL
;
1379 m_pFileStream
->Seek(10L);
1380 (*m_pFileStream
) << nRecLength
; // set record length afterwards
1384 m_pFileStream
->Seek(0L);
1385 if (nDbaseType
== VisualFoxPro
)
1386 (*m_pFileStream
) << (sal_uInt8
) FoxProMemo
;
1388 (*m_pFileStream
) << (sal_uInt8
) dBaseIIIMemo
;
1389 } // if (bCreateMemo)
1391 catch ( const Exception
& e
)
1397 // we have to drop the file because it is corrupted now
1400 catch(const Exception
&) { }
1406 //------------------------------------------------------------------
1407 // creates in principle dBase III file format
1408 sal_Bool
ODbaseTable::CreateMemoFile(const INetURLObject
& aFile
)
1410 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::CreateMemoFile" );
1411 // filehandling macro for table creation
1412 m_pMemoStream
= createStream_simpleError( aFile
.GetMainURL(INetURLObject::NO_DECODE
),STREAM_READWRITE
| STREAM_SHARE_DENYWRITE
);
1417 m_pMemoStream
->SetStreamSize(512);
1419 m_pMemoStream
->Seek(0L);
1420 (*m_pMemoStream
) << sal_uInt32(1); // pointer to the first free block
1422 m_pMemoStream
->Flush();
1423 delete m_pMemoStream
;
1424 m_pMemoStream
= NULL
;
1427 //------------------------------------------------------------------
1428 sal_Bool
ODbaseTable::Drop_Static(const OUString
& _sUrl
,sal_Bool _bHasMemoFields
,OCollection
* _pIndexes
)
1430 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::Drop_Static" );
1434 sal_Bool bDropped
= ::utl::UCBContentHelper::Kill(aURL
.GetMainURL(INetURLObject::NO_DECODE
));
1438 if (_bHasMemoFields
)
1439 { // delete the memo fields
1440 aURL
.setExtension("dbt");
1441 bDropped
= ::utl::UCBContentHelper::Kill(aURL
.GetMainURL(INetURLObject::NO_DECODE
));
1450 sal_Int32 i
= _pIndexes
->getCount();
1453 _pIndexes
->dropByIndex(--i
);
1456 catch(const SQLException
&)
1460 aURL
.setExtension("inf");
1462 // as the inf file does not necessarily exist, we aren't allowed to use UCBContentHelper::Kill
1465 ::ucbhelper::Content
aDeleteContent( aURL
.GetMainURL( INetURLObject::NO_DECODE
), Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
1466 aDeleteContent
.executeCommand( "delete", makeAny( sal_Bool( sal_True
) ) );
1468 catch(const Exception
&)
1470 // silently ignore this ....
1476 // -----------------------------------------------------------------------------
1477 sal_Bool
ODbaseTable::DropImpl()
1479 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::DropImpl" );
1483 refreshIndexes(); // look for indexes which must be deleted as well
1485 sal_Bool bDropped
= Drop_Static(getEntry(m_pConnection
,m_Name
),HasMemoFields(),m_pIndexes
);
1487 {// we couldn't drop the table so we have to reopen it
1490 m_pColumns
->refresh();
1495 //------------------------------------------------------------------
1496 sal_Bool
ODbaseTable::InsertRow(OValueRefVector
& rRow
, sal_Bool bFlush
,const Reference
<XIndexAccess
>& _xCols
)
1498 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::InsertRow" );
1499 // fill buffer with blanks
1501 memset(m_pBuffer
, 0, m_aHeader
.db_slng
);
1504 // Copy new row completely:
1505 // ... and add at the end as new Record:
1506 sal_uInt32 nTempPos
= m_nFilePos
;
1508 m_nFilePos
= (sal_uIntPtr
)m_aHeader
.db_anz
+ 1;
1509 sal_Bool bInsertRow
= UpdateBuffer( rRow
, NULL
, _xCols
, true );
1512 sal_uInt32 nFileSize
= 0, nMemoFileSize
= 0;
1514 nFileSize
= lcl_getFileSize(*m_pFileStream
);
1516 if (HasMemoFields() && m_pMemoStream
)
1518 m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
1519 nMemoFileSize
= m_pMemoStream
->Tell();
1524 m_pFileStream
->SetStreamSize(nFileSize
); // restore old size
1526 if (HasMemoFields() && m_pMemoStream
)
1527 m_pMemoStream
->SetStreamSize(nMemoFileSize
); // restore old size
1528 m_nFilePos
= nTempPos
; // restore file position
1532 (*m_pFileStream
) << (char)DBF_EOL
; // write EOL
1533 // raise number of datasets in the header:
1534 m_pFileStream
->Seek( 4L );
1535 (*m_pFileStream
) << (m_aHeader
.db_anz
+ 1);
1537 // if AppendOnly no flush!
1539 m_pFileStream
->Flush();
1541 // raise number if successfully
1543 *rRow
.get()[0] = m_nFilePos
; // set bookmark
1544 m_nFilePos
= nTempPos
;
1548 m_nFilePos
= nTempPos
;
1553 //------------------------------------------------------------------
1554 sal_Bool
ODbaseTable::UpdateRow(OValueRefVector
& rRow
, OValueRefRow
& pOrgRow
,const Reference
<XIndexAccess
>& _xCols
)
1556 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::UpdateRow" );
1557 // fill buffer with blanks
1560 // position on desired record:
1561 long nPos
= m_aHeader
.db_kopf
+ (long)(m_nFilePos
-1) * m_aHeader
.db_slng
;
1562 m_pFileStream
->Seek(nPos
);
1563 m_pFileStream
->Read((char*)m_pBuffer
, m_aHeader
.db_slng
);
1565 sal_uInt32
nMemoFileSize( 0 );
1566 if (HasMemoFields() && m_pMemoStream
)
1568 m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
1569 nMemoFileSize
= m_pMemoStream
->Tell();
1571 if (!UpdateBuffer(rRow
, pOrgRow
, _xCols
, false) || !WriteBuffer())
1573 if (HasMemoFields() && m_pMemoStream
)
1574 m_pMemoStream
->SetStreamSize(nMemoFileSize
); // restore old size
1578 m_pFileStream
->Flush();
1583 //------------------------------------------------------------------
1584 sal_Bool
ODbaseTable::DeleteRow(const OSQLColumns
& _rCols
)
1586 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::DeleteRow" );
1587 // Set the Delete-Flag (be it set or not):
1588 // Position on desired record:
1589 long nFilePos
= m_aHeader
.db_kopf
+ (long)(m_nFilePos
-1) * m_aHeader
.db_slng
;
1590 m_pFileStream
->Seek(nFilePos
);
1592 OValueRefRow aRow
= new OValueRefVector(_rCols
.get().size());
1594 if (!fetchRow(aRow
,_rCols
,sal_True
,sal_True
))
1597 Reference
<XPropertySet
> xCol
;
1599 ::comphelper::UStringMixEqual
aCase(isCaseSensitive());
1600 for (sal_uInt16 i
= 0; i
< m_pColumns
->getCount(); i
++)
1602 Reference
<XPropertySet
> xIndex
= isUniqueByColumnName(i
);
1605 ::cppu::extractInterface(xCol
,m_pColumns
->getByIndex(i
));
1606 OSL_ENSURE(xCol
.is(),"ODbaseTable::DeleteRow column is null!");
1609 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1611 Reference
<XUnoTunnel
> xTunnel(xIndex
,UNO_QUERY
);
1612 OSL_ENSURE(xTunnel
.is(),"No TunnelImplementation!");
1613 ODbaseIndex
* pIndex
= reinterpret_cast< ODbaseIndex
* >( xTunnel
->getSomething(ODbaseIndex::getUnoTunnelImplementationId()) );
1614 OSL_ENSURE(pIndex
,"ODbaseTable::DeleteRow: No Index returned!");
1616 OSQLColumns::Vector::const_iterator aIter
= _rCols
.get().begin();
1618 for(;aIter
!= _rCols
.get().end();++aIter
,++nPos
)
1620 if(aCase(getString((*aIter
)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME
))),aColName
))
1623 if (aIter
== _rCols
.get().end())
1626 pIndex
->Delete(m_nFilePos
,*(aRow
->get())[nPos
]);
1631 m_pFileStream
->Seek(nFilePos
);
1632 (*m_pFileStream
) << (sal_uInt8
)'*'; // mark the row in the table as deleted
1633 m_pFileStream
->Flush();
1636 // -------------------------------------------------------------------------
1637 Reference
<XPropertySet
> ODbaseTable::isUniqueByColumnName(sal_Int32 _nColumnPos
)
1639 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::isUniqueByColumnName" );
1642 if(m_pIndexes
->hasElements())
1644 Reference
<XPropertySet
> xCol
;
1645 m_pColumns
->getByIndex(_nColumnPos
) >>= xCol
;
1646 OSL_ENSURE(xCol
.is(),"ODbaseTable::isUniqueByColumnName column is null!");
1648 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= sColName
;
1650 Reference
<XPropertySet
> xIndex
;
1651 for(sal_Int32 i
=0;i
<m_pIndexes
->getCount();++i
)
1653 ::cppu::extractInterface(xIndex
,m_pIndexes
->getByIndex(i
));
1654 if(xIndex
.is() && getBOOL(xIndex
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE
))))
1656 Reference
<XNameAccess
> xCols(Reference
<XColumnsSupplier
>(xIndex
,UNO_QUERY
)->getColumns());
1657 if(xCols
->hasByName(sColName
))
1663 return Reference
<XPropertySet
>();
1665 //------------------------------------------------------------------
1666 static double toDouble(const OString
& rString
)
1668 return ::rtl::math::stringToDouble( rString
, '.', ',', NULL
, NULL
);
1671 //------------------------------------------------------------------
1672 sal_Bool
ODbaseTable::UpdateBuffer(OValueRefVector
& rRow
, OValueRefRow pOrgRow
, const Reference
<XIndexAccess
>& _xCols
, const bool bForceAllFields
)
1674 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::UpdateBuffer" );
1675 OSL_ENSURE(m_pBuffer
,"Buffer is NULL!");
1678 sal_Int32 nByteOffset
= 1;
1681 Reference
<XPropertySet
> xCol
;
1682 Reference
<XPropertySet
> xIndex
;
1685 const sal_Int32 nColumnCount
= m_pColumns
->getCount();
1686 ::std::vector
< Reference
<XPropertySet
> > aIndexedCols(nColumnCount
);
1688 ::comphelper::UStringMixEqual
aCase(isCaseSensitive());
1690 Reference
<XIndexAccess
> xColumns
= m_pColumns
;
1691 // first search a key that exist already in the table
1692 for (i
= 0; i
< nColumnCount
; ++i
)
1695 if(_xCols
!= xColumns
)
1697 m_pColumns
->getByIndex(i
) >>= xCol
;
1698 OSL_ENSURE(xCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1699 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1701 for(nPos
= 0;nPos
<_xCols
->getCount();++nPos
)
1703 Reference
<XPropertySet
> xFindCol
;
1704 ::cppu::extractInterface(xFindCol
,_xCols
->getByIndex(nPos
));
1705 OSL_ENSURE(xFindCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1706 if(aCase(getString(xFindCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
))),aColName
))
1709 if (nPos
>= _xCols
->getCount())
1714 xIndex
= isUniqueByColumnName(i
);
1715 aIndexedCols
[i
] = xIndex
;
1718 // first check if the value is different to the old one and when if it conform to the index
1719 if(pOrgRow
.is() && (rRow
.get()[nPos
]->getValue().isNull() || rRow
.get()[nPos
] == (pOrgRow
->get())[nPos
]))
1723 Reference
<XUnoTunnel
> xTunnel(xIndex
,UNO_QUERY
);
1724 OSL_ENSURE(xTunnel
.is(),"No TunnelImplementation!");
1725 ODbaseIndex
* pIndex
= reinterpret_cast< ODbaseIndex
* >( xTunnel
->getSomething(ODbaseIndex::getUnoTunnelImplementationId()) );
1726 OSL_ENSURE(pIndex
,"ODbaseTable::UpdateBuffer: No Index returned!");
1728 if (pIndex
->Find(0,*rRow
.get()[nPos
]))
1730 // There is no unique value
1731 if ( aColName
.isEmpty() )
1733 m_pColumns
->getByIndex(i
) >>= xCol
;
1734 OSL_ENSURE(xCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1735 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1737 } // if ( !aColName.getLength() )
1738 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1739 STR_DUPLICATE_VALUE_IN_COLUMN
1740 ,"$columnname$", aColName
1742 ::dbtools::throwGenericSQLException( sError
, *this );
1748 // when we are here there is no double key in the table
1750 for (i
= 0; i
< nColumnCount
&& nByteOffset
<= m_nBufferSize
; ++i
)
1752 // Lengths for each data type:
1753 OSL_ENSURE(i
< m_aPrecisions
.size(),"Illegal index!");
1755 sal_Int32 nType
= 0;
1756 sal_Int32 nScale
= 0;
1757 if ( i
< m_aPrecisions
.size() )
1759 nLen
= m_aPrecisions
[i
];
1760 nType
= m_aTypes
[i
];
1761 nScale
= m_aScales
[i
];
1765 m_pColumns
->getByIndex(i
) >>= xCol
;
1768 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION
)) >>= nLen
;
1769 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
)) >>= nType
;
1770 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
)) >>= nScale
;
1774 bool bSetZero
= false;
1777 case DataType::INTEGER
:
1778 case DataType::DOUBLE
:
1779 case DataType::TIMESTAMP
:
1781 case DataType::LONGVARBINARY
:
1782 case DataType::DATE
:
1784 case DataType::LONGVARCHAR
:
1785 nLen
= m_aRealFieldLengths
[i
];
1787 case DataType::DECIMAL
:
1788 nLen
= SvDbaseConverter::ConvertPrecisionToDbase(nLen
,nScale
);
1789 break; // The sign and the comma
1796 if(_xCols
!= xColumns
)
1798 m_pColumns
->getByIndex(i
) >>= xCol
;
1799 OSL_ENSURE(xCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1800 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1801 for(nPos
= 0;nPos
<_xCols
->getCount();++nPos
)
1803 Reference
<XPropertySet
> xFindCol
;
1804 ::cppu::extractInterface(xFindCol
,_xCols
->getByIndex(nPos
));
1805 if(aCase(getString(xFindCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
))),aColName
))
1808 if (nPos
>= _xCols
->getCount())
1810 nByteOffset
+= nLen
;
1817 ++nPos
; // the row values start at 1
1818 const ORowSetValue
&thisColVal
= rRow
.get()[nPos
]->get();
1819 const bool thisColIsBound
= thisColVal
.isBound();
1820 const bool thisColIsNull
= !thisColIsBound
|| thisColVal
.isNull();
1821 // don't overwrite non-bound columns
1822 if ( ! (bForceAllFields
|| thisColIsBound
) )
1824 // No - don't overwrite this field, it has not changed.
1825 nByteOffset
+= nLen
;
1828 if (aIndexedCols
[i
].is())
1830 Reference
<XUnoTunnel
> xTunnel(aIndexedCols
[i
],UNO_QUERY
);
1831 OSL_ENSURE(xTunnel
.is(),"No TunnelImplementation!");
1832 ODbaseIndex
* pIndex
= reinterpret_cast< ODbaseIndex
* >( xTunnel
->getSomething(ODbaseIndex::getUnoTunnelImplementationId()) );
1833 OSL_ENSURE(pIndex
,"ODbaseTable::UpdateBuffer: No Index returned!");
1835 if (pOrgRow
.is() && !thisColIsNull
)
1836 pIndex
->Update(m_nFilePos
, *(pOrgRow
->get())[nPos
], thisColVal
);
1838 pIndex
->Insert(m_nFilePos
, thisColVal
);
1841 char* pData
= (char *)(m_pBuffer
+ nByteOffset
);
1845 memset(pData
,0,nLen
); // Clear to NULL char ('\0')
1847 memset(pData
,' ',nLen
); // Clear to space/blank ('\0x20')
1848 nByteOffset
+= nLen
;
1849 OSL_ENSURE( nByteOffset
<= m_nBufferSize
,"ByteOffset > m_nBufferSize!");
1857 case DataType::TIMESTAMP
:
1859 sal_Int32 nJulianDate
= 0, nJulianTime
= 0;
1860 lcl_CalcJulDate(nJulianDate
,nJulianTime
, thisColVal
);
1861 // Exactly 8 bytes to copy:
1862 memcpy(pData
,&nJulianDate
,4);
1863 memcpy(pData
+4,&nJulianTime
,4);
1866 case DataType::DATE
:
1868 ::com::sun::star::util::Date aDate
;
1869 if(thisColVal
.getTypeKind() == DataType::DOUBLE
)
1870 aDate
= ::dbtools::DBTypeConversion::toDate(thisColVal
.getDouble());
1881 // Exactly 8 bytes to copy:
1882 strncpy(pData
,s
,sizeof s
- 1);
1884 case DataType::INTEGER
:
1886 sal_Int32 nValue
= thisColVal
;
1887 memcpy(pData
,&nValue
,nLen
);
1890 case DataType::DOUBLE
:
1892 const double d
= thisColVal
;
1893 m_pColumns
->getByIndex(i
) >>= xCol
;
1895 if (getBOOL(xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY
)))) // Currency is treated separately
1897 sal_Int64 nValue
= 0;
1899 nValue
= (sal_Int64
)(d
* pow(10.0,(int)m_aScales
[i
]));
1901 nValue
= (sal_Int64
)(d
);
1902 memcpy(pData
,&nValue
,nLen
);
1903 } // if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency is treated separately
1905 memcpy(pData
,&d
,nLen
);
1908 case DataType::DECIMAL
:
1910 memset(pData
,' ',nLen
); // Clear to NULL
1912 const double n
= thisColVal
;
1914 // one, because const_cast GetFormatPrecision on SvNumberFormat is not constant,
1915 // even though it really could and should be
1916 const OString
aDefaultValue( ::rtl::math::doubleToString( n
, rtl_math_StringFormat_F
, nScale
, '.', NULL
, 0));
1917 const sal_Int32 nValueLen
= aDefaultValue
.getLength();
1918 if ( nValueLen
<= nLen
)
1920 // Write value right-justified, padded with blanks to the left.
1921 memcpy(pData
+nLen
-nValueLen
,aDefaultValue
.getStr(),nValueLen
);
1922 // write the resulting double back
1923 *rRow
.get()[nPos
] = toDouble(aDefaultValue
);
1927 m_pColumns
->getByIndex(i
) >>= xCol
;
1928 OSL_ENSURE(xCol
.is(),"ODbaseTable::UpdateBuffer column is null!");
1929 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1930 ::std::list
< ::std::pair
<const sal_Char
* , OUString
> > aStringToSubstitutes
;
1931 aStringToSubstitutes
.push_back(::std::pair
<const sal_Char
* , OUString
>("$columnname$", aColName
));
1932 aStringToSubstitutes
.push_back(::std::pair
<const sal_Char
* , OUString
>("$precision$", OUString::number(nLen
)));
1933 aStringToSubstitutes
.push_back(::std::pair
<const sal_Char
* , OUString
>("$scale$", OUString::number(nScale
)));
1934 aStringToSubstitutes
.push_back(::std::pair
<const sal_Char
* , OUString
>("$value$", OStringToOUString(aDefaultValue
,RTL_TEXTENCODING_UTF8
)));
1936 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1937 STR_INVALID_COLUMN_DECIMAL_VALUE
1938 ,aStringToSubstitutes
1940 ::dbtools::throwGenericSQLException( sError
, *this );
1944 *pData
= thisColVal
.getBool() ? 'T' : 'F';
1946 case DataType::LONGVARBINARY
:
1947 case DataType::LONGVARCHAR
:
1949 char cNext
= pData
[nLen
]; // Mark's scratch and replaced by 0
1950 pData
[nLen
] = '\0'; // This is because the buffer is always a sign of greater ...
1952 sal_uIntPtr nBlockNo
= strtol((const char *)pData
,NULL
,10); // Block number read
1954 // Next initial character restore again:
1955 pData
[nLen
] = cNext
;
1956 if (!m_pMemoStream
|| !WriteMemo(thisColVal
, nBlockNo
))
1959 OString
aBlock(OString::number(nBlockNo
));
1960 //align aBlock at the right of a nLen sequence, fill to the left with '0'
1962 comphelper::string::padToLength(aStr
, nLen
- aBlock
.getLength(), '0');
1963 aStr
.append(aBlock
);
1966 memcpy(pData
, aStr
.getStr(), nLen
);
1970 memset(pData
,' ',nLen
); // Clear to NULL
1972 OUString
sStringToWrite( thisColVal
.getString() );
1974 // convert the string, using the connection's encoding
1977 DBTypeConversion::convertUnicodeStringToLength( sStringToWrite
, sEncoded
, nLen
, m_eEncoding
);
1978 memcpy( pData
, sEncoded
.getStr(), sEncoded
.getLength() );
1984 catch( const SQLException
& )
1988 catch ( const Exception
& )
1990 m_pColumns
->getByIndex(i
) >>= xCol
;
1991 OSL_ENSURE( xCol
.is(), "ODbaseTable::UpdateBuffer column is null!" );
1993 xCol
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= aColName
;
1995 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
1996 STR_INVALID_COLUMN_VALUE
,
1997 "$columnname$", aColName
1999 ::dbtools::throwGenericSQLException( sError
, *this );
2002 nByteOffset
+= nLen
;
2003 OSL_ENSURE( nByteOffset
<= m_nBufferSize
,"ByteOffset > m_nBufferSize!");
2008 // -----------------------------------------------------------------------------
2009 sal_Bool
ODbaseTable::WriteMemo(const ORowSetValue
& aVariable
, sal_uIntPtr
& rBlockNr
)
2011 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::WriteMemo" );
2012 // if the BlockNo 0 is given, the block will be appended at the end
2013 sal_uIntPtr nSize
= 0;
2015 ::com::sun::star::uno::Sequence
<sal_Int8
> aValue
;
2016 sal_uInt8 nHeader
[4];
2017 const bool bBinary
= aVariable
.getTypeKind() == DataType::LONGVARBINARY
&& m_aMemoHeader
.db_typ
== MemoFoxPro
;
2020 aValue
= aVariable
.getSequence();
2021 nSize
= aValue
.getLength();
2025 nSize
= DBTypeConversion::convertUnicodeString( aVariable
.getString(), aStr
, m_eEncoding
);
2028 // append or overwrite
2029 sal_Bool bAppend
= rBlockNr
== 0;
2033 switch (m_aMemoHeader
.db_typ
)
2035 case MemodBaseIII
: // dBase III-Memofield, ends with 2 * Ctrl-Z
2036 bAppend
= nSize
> (512 - 2);
2039 case MemodBaseIV
: // dBase IV-Memofield with length
2042 m_pMemoStream
->Seek(rBlockNr
* m_aMemoHeader
.db_size
);
2043 m_pMemoStream
->SeekRel(4L);
2044 m_pMemoStream
->Read(sHeader
,4);
2046 sal_uIntPtr nOldSize
;
2047 if (m_aMemoHeader
.db_typ
== MemoFoxPro
)
2048 nOldSize
= ((((unsigned char)sHeader
[0]) * 256 +
2049 (unsigned char)sHeader
[1]) * 256 +
2050 (unsigned char)sHeader
[2]) * 256 +
2051 (unsigned char)sHeader
[3];
2053 nOldSize
= ((((unsigned char)sHeader
[3]) * 256 +
2054 (unsigned char)sHeader
[2]) * 256 +
2055 (unsigned char)sHeader
[1]) * 256 +
2056 (unsigned char)sHeader
[0] - 8;
2058 // fits the new length in the used blocks
2059 sal_uIntPtr nUsedBlocks
= ((nSize
+ 8) / m_aMemoHeader
.db_size
) + (((nSize
+ 8) % m_aMemoHeader
.db_size
> 0) ? 1 : 0),
2060 nOldUsedBlocks
= ((nOldSize
+ 8) / m_aMemoHeader
.db_size
) + (((nOldSize
+ 8) % m_aMemoHeader
.db_size
> 0) ? 1 : 0);
2061 bAppend
= nUsedBlocks
> nOldUsedBlocks
;
2068 sal_uIntPtr nStreamSize
= m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
2070 rBlockNr
= (nStreamSize
/ m_aMemoHeader
.db_size
) + ((nStreamSize
% m_aMemoHeader
.db_size
) > 0 ? 1 : 0);
2072 m_pMemoStream
->SetStreamSize(rBlockNr
* m_aMemoHeader
.db_size
);
2073 m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
2077 m_pMemoStream
->Seek(rBlockNr
* m_aMemoHeader
.db_size
);
2080 switch (m_aMemoHeader
.db_typ
)
2082 case MemodBaseIII
: // dBase III-Memofield, ends with Ctrl-Z
2084 const char cEOF
= (char) DBF_EOL
;
2086 m_pMemoStream
->Write( aStr
.getStr(), aStr
.getLength() );
2087 (*m_pMemoStream
) << cEOF
<< cEOF
;
2090 case MemodBaseIV
: // dBase IV-Memofeld with length
2092 if ( MemodBaseIV
== m_aMemoHeader
.db_typ
)
2093 (*m_pMemoStream
) << (sal_uInt8
)0xFF
2097 (*m_pMemoStream
) << (sal_uInt8
)0x00
2101 sal_uInt32 nWriteSize
= nSize
;
2102 if (m_aMemoHeader
.db_typ
== MemoFoxPro
)
2105 (*m_pMemoStream
) << (sal_uInt8
) 0x00; // Picture
2107 (*m_pMemoStream
) << (sal_uInt8
) 0x01; // Memo
2108 for (int i
= 4; i
> 0; nWriteSize
>>= 8)
2109 nHeader
[--i
] = (sal_uInt8
) (nWriteSize
% 256);
2113 (*m_pMemoStream
) << (sal_uInt8
) 0x00;
2115 for (int i
= 0; i
< 4; nWriteSize
>>= 8)
2116 nHeader
[i
++] = (sal_uInt8
) (nWriteSize
% 256);
2119 m_pMemoStream
->Write(nHeader
,4);
2121 m_pMemoStream
->Write( aValue
.getConstArray(), aValue
.getLength() );
2123 m_pMemoStream
->Write( aStr
.getStr(), aStr
.getLength() );
2124 m_pMemoStream
->Flush();
2129 // Write the new block number
2132 sal_uIntPtr nStreamSize
= m_pMemoStream
->Seek(STREAM_SEEK_TO_END
);
2133 m_aMemoHeader
.db_next
= (nStreamSize
/ m_aMemoHeader
.db_size
) + ((nStreamSize
% m_aMemoHeader
.db_size
) > 0 ? 1 : 0);
2135 // Write the new block number
2136 m_pMemoStream
->Seek(0L);
2137 (*m_pMemoStream
) << m_aMemoHeader
.db_next
;
2138 m_pMemoStream
->Flush();
2143 // -----------------------------------------------------------------------------
2145 void SAL_CALL
ODbaseTable::alterColumnByName( const OUString
& colName
, const Reference
< XPropertySet
>& descriptor
) throw(SQLException
, NoSuchElementException
, RuntimeException
)
2147 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::alterColumnByName" );
2148 ::osl::MutexGuard
aGuard(m_aMutex
);
2149 checkDisposed(OTableDescriptor_BASE::rBHelper
.bDisposed
);
2152 Reference
<XDataDescriptorFactory
> xOldColumn
;
2153 m_pColumns
->getByName(colName
) >>= xOldColumn
;
2155 alterColumn(m_pColumns
->findColumn(colName
)-1,descriptor
,xOldColumn
);
2157 // -------------------------------------------------------------------------
2158 void SAL_CALL
ODbaseTable::alterColumnByIndex( sal_Int32 index
, const Reference
< XPropertySet
>& descriptor
) throw(SQLException
, ::com::sun::star::lang::IndexOutOfBoundsException
, RuntimeException
)
2160 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::alterColumnByIndex" );
2161 ::osl::MutexGuard
aGuard(m_aMutex
);
2162 checkDisposed(OTableDescriptor_BASE::rBHelper
.bDisposed
);
2164 if(index
< 0 || index
>= m_pColumns
->getCount())
2165 throw IndexOutOfBoundsException(OUString::number(index
),*this);
2167 Reference
<XDataDescriptorFactory
> xOldColumn
;
2168 m_pColumns
->getByIndex(index
) >>= xOldColumn
;
2169 alterColumn(index
,descriptor
,xOldColumn
);
2171 // -----------------------------------------------------------------------------
2172 void ODbaseTable::alterColumn(sal_Int32 index
,
2173 const Reference
< XPropertySet
>& descriptor
,
2174 const Reference
< XDataDescriptorFactory
>& xOldColumn
)
2176 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::alterColumn" );
2177 if(index
< 0 || index
>= m_pColumns
->getCount())
2178 throw IndexOutOfBoundsException(OUString::number(index
),*this);
2180 ODbaseTable
* pNewTable
= NULL
;
2183 OSL_ENSURE(descriptor
.is(),"ODbaseTable::alterColumn: descriptor can not be null!");
2184 // creates a copy of the original column and copy all properties from descriptor in xCopyColumn
2185 Reference
<XPropertySet
> xCopyColumn
;
2187 xCopyColumn
= xOldColumn
->createDataDescriptor();
2189 xCopyColumn
= new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2191 ::comphelper::copyProperties(descriptor
,xCopyColumn
);
2193 // creates a temp file
2195 String sTempName
= createTempFile();
2197 pNewTable
= new ODbaseTable(m_pTables
,static_cast<ODbaseConnection
*>(m_pConnection
));
2198 Reference
<XPropertySet
> xHoldTable
= pNewTable
;
2199 pNewTable
->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
),makeAny(OUString(sTempName
)));
2200 Reference
<XAppend
> xAppend(pNewTable
->getColumns(),UNO_QUERY
);
2201 OSL_ENSURE(xAppend
.is(),"ODbaseTable::alterColumn: No XAppend interface!");
2203 // copy the structure
2207 Reference
<XPropertySet
> xProp
;
2208 m_pColumns
->getByIndex(i
) >>= xProp
;
2209 Reference
<XDataDescriptorFactory
> xColumn(xProp
,UNO_QUERY
);
2210 Reference
<XPropertySet
> xCpy
;
2212 xCpy
= xColumn
->createDataDescriptor();
2214 xCpy
= new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2215 ::comphelper::copyProperties(xProp
,xCpy
);
2216 xAppend
->appendByDescriptor(xCpy
);
2218 ++i
; // now insert our new column
2219 xAppend
->appendByDescriptor(xCopyColumn
);
2221 for(;i
< m_pColumns
->getCount();++i
)
2223 Reference
<XPropertySet
> xProp
;
2224 m_pColumns
->getByIndex(i
) >>= xProp
;
2225 Reference
<XDataDescriptorFactory
> xColumn(xProp
,UNO_QUERY
);
2226 Reference
<XPropertySet
> xCpy
;
2228 xCpy
= xColumn
->createDataDescriptor();
2230 xCpy
= new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2231 ::comphelper::copyProperties(xProp
,xCpy
);
2232 xAppend
->appendByDescriptor(xCpy
);
2235 // construct the new table
2236 if(!pNewTable
->CreateImpl())
2238 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2239 STR_COLUMN_NOT_ALTERABLE
,
2240 "$columnname$", ::comphelper::getString(descriptor
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)))
2242 ::dbtools::throwGenericSQLException( sError
, *this );
2245 pNewTable
->construct();
2248 copyData(pNewTable
,0);
2250 // now drop the old one
2251 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
);
2255 // release the temp file
2257 ::comphelper::disposeComponent(xHoldTable
);
2266 m_pColumns
->refresh();
2269 catch(const SQLException
&)
2273 catch(const Exception
&)
2275 OSL_FAIL("ODbaseTable::alterColumn: Exception occurred!");
2279 // -----------------------------------------------------------------------------
2280 Reference
< XDatabaseMetaData
> ODbaseTable::getMetaData() const
2282 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getMetaData" );
2283 return getConnection()->getMetaData();
2285 // -------------------------------------------------------------------------
2286 void SAL_CALL
ODbaseTable::rename( const OUString
& newName
) throw(::com::sun::star::sdbc::SQLException
, ::com::sun::star::container::ElementExistException
, ::com::sun::star::uno::RuntimeException
)
2288 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::rename" );
2289 ::osl::MutexGuard
aGuard(m_aMutex
);
2290 checkDisposed(OTableDescriptor_BASE::rBHelper
.bDisposed
);
2291 if(m_pTables
&& m_pTables
->hasByName(newName
))
2292 throw ElementExistException(newName
,*this);
2295 renameImpl(newName
);
2297 ODbaseTable_BASE::rename(newName
);
2301 m_pColumns
->refresh();
2305 void renameFile(OConnection
* _pConenction
,const OUString
& oldName
,
2306 const OUString
& newName
,const String
& _sExtension
)
2308 String aName
= ODbaseTable::getEntry(_pConenction
,oldName
);
2311 OUString aIdent
= _pConenction
->getContent()->getIdentifier()->getContentIdentifier();
2312 if ( aIdent
.lastIndexOf('/') != (aIdent
.getLength()-1) )
2313 aIdent
+= OUString("/");
2320 aURL
.setExtension( _sExtension
);
2321 OUString
sNewName(newName
);
2323 sNewName
+= _sExtension
;
2327 Content
aContent(aURL
.GetMainURL(INetURLObject::NO_DECODE
),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
2329 Sequence
< PropertyValue
> aProps( 1 );
2330 aProps
[0].Name
= "Title";
2331 aProps
[0].Handle
= -1; // n/a
2332 aProps
[0].Value
= makeAny( OUString(sNewName
) );
2333 Sequence
< Any
> aValues
;
2334 aContent
.executeCommand( "setPropertyValues",makeAny(aProps
) ) >>= aValues
;
2335 if(aValues
.getLength() && aValues
[0].hasValue())
2338 catch(const Exception
&)
2340 throw ElementExistException(newName
,NULL
);
2344 // -------------------------------------------------------------------------
2345 void SAL_CALL
ODbaseTable::renameImpl( const OUString
& newName
) throw(::com::sun::star::sdbc::SQLException
, ::com::sun::star::container::ElementExistException
, ::com::sun::star::uno::RuntimeException
)
2347 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getEntry" );
2348 ::osl::MutexGuard
aGuard(m_aMutex
);
2353 renameFile(m_pConnection
,m_Name
,newName
,m_pConnection
->getExtension());
2354 if ( HasMemoFields() )
2355 { // delete the memo fields
2356 OUString
sExt("dbt");
2357 renameFile(m_pConnection
,m_Name
,newName
,sExt
);
2360 // -----------------------------------------------------------------------------
2361 void ODbaseTable::addColumn(const Reference
< XPropertySet
>& _xNewColumn
)
2363 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::addColumn" );
2364 String sTempName
= createTempFile();
2366 ODbaseTable
* pNewTable
= new ODbaseTable(m_pTables
,static_cast<ODbaseConnection
*>(m_pConnection
));
2367 Reference
< XPropertySet
> xHold
= pNewTable
;
2368 pNewTable
->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
),makeAny(OUString(sTempName
)));
2370 Reference
<XAppend
> xAppend(pNewTable
->getColumns(),UNO_QUERY
);
2371 sal_Bool bCase
= getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
2372 // copy the structure
2373 for(sal_Int32 i
=0;i
< m_pColumns
->getCount();++i
)
2375 Reference
<XPropertySet
> xProp
;
2376 m_pColumns
->getByIndex(i
) >>= xProp
;
2377 Reference
<XDataDescriptorFactory
> xColumn(xProp
,UNO_QUERY
);
2378 Reference
<XPropertySet
> xCpy
;
2380 xCpy
= xColumn
->createDataDescriptor();
2383 xCpy
= new OColumn(bCase
);
2384 ::comphelper::copyProperties(xProp
,xCpy
);
2387 xAppend
->appendByDescriptor(xCpy
);
2389 Reference
<XPropertySet
> xCpy
= new OColumn(bCase
);
2390 ::comphelper::copyProperties(_xNewColumn
,xCpy
);
2391 xAppend
->appendByDescriptor(xCpy
);
2394 // construct the new table
2395 if(!pNewTable
->CreateImpl())
2397 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2398 STR_COLUMN_NOT_ADDABLE
,
2399 "$columnname$", ::comphelper::getString(_xNewColumn
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)))
2401 ::dbtools::throwGenericSQLException( sError
, *this );
2404 sal_Bool bAlreadyDroped
= sal_False
;
2407 pNewTable
->construct();
2409 copyData(pNewTable
,pNewTable
->m_pColumns
->getCount());
2410 // drop the old table
2413 bAlreadyDroped
= sal_True
;
2414 pNewTable
->renameImpl(m_Name
);
2415 // release the temp file
2417 xHold
= pNewTable
= NULL
;
2422 m_pColumns
->refresh();
2424 catch(const SQLException
&)
2426 // here we know that the old table wasn't droped before
2428 xHold
= pNewTable
= NULL
;
2433 // -----------------------------------------------------------------------------
2434 void ODbaseTable::dropColumn(sal_Int32 _nPos
)
2436 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::dropColumn" );
2437 String sTempName
= createTempFile();
2439 ODbaseTable
* pNewTable
= new ODbaseTable(m_pTables
,static_cast<ODbaseConnection
*>(m_pConnection
));
2440 Reference
< XPropertySet
> xHold
= pNewTable
;
2441 pNewTable
->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
),makeAny(OUString(sTempName
)));
2443 Reference
<XAppend
> xAppend(pNewTable
->getColumns(),UNO_QUERY
);
2444 sal_Bool bCase
= getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
2445 // copy the structure
2446 for(sal_Int32 i
=0;i
< m_pColumns
->getCount();++i
)
2450 Reference
<XPropertySet
> xProp
;
2451 m_pColumns
->getByIndex(i
) >>= xProp
;
2452 Reference
<XDataDescriptorFactory
> xColumn(xProp
,UNO_QUERY
);
2453 Reference
<XPropertySet
> xCpy
;
2455 xCpy
= xColumn
->createDataDescriptor();
2458 xCpy
= new OColumn(bCase
);
2459 ::comphelper::copyProperties(xProp
,xCpy
);
2461 xAppend
->appendByDescriptor(xCpy
);
2466 // construct the new table
2467 if(!pNewTable
->CreateImpl())
2469 xHold
= pNewTable
= NULL
;
2470 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2471 STR_COLUMN_NOT_DROP
,
2472 "$position$", OUString::number(_nPos
)
2474 ::dbtools::throwGenericSQLException( sError
, *this );
2476 pNewTable
->construct();
2478 copyData(pNewTable
,_nPos
);
2479 // drop the old table
2481 pNewTable
->renameImpl(m_Name
);
2482 // release the temp file
2484 xHold
= pNewTable
= NULL
;
2489 // -----------------------------------------------------------------------------
2490 String
ODbaseTable::createTempFile()
2492 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::createTempFile" );
2493 OUString aIdent
= m_pConnection
->getContent()->getIdentifier()->getContentIdentifier();
2494 if ( aIdent
.lastIndexOf('/') != (aIdent
.getLength()-1) )
2496 String
sTempName(aIdent
);
2498 sExt
.AssignAscii(".");
2499 sExt
+= m_pConnection
->getExtension();
2501 String
sName(m_Name
);
2502 TempFile
aTempFile(sName
,&sExt
,&sTempName
);
2503 if(!aTempFile
.IsValid())
2504 getConnection()->throwGenericSQLException(STR_COULD_NOT_ALTER_TABLE
,*this);
2507 aURL
.SetSmartProtocol(INET_PROT_FILE
);
2508 aURL
.SetURL(aTempFile
.GetURL());
2510 String
sNewName(aURL
.getName());
2511 sNewName
.Erase(sNewName
.Len() - sExt
.Len());
2514 // -----------------------------------------------------------------------------
2515 void ODbaseTable::copyData(ODbaseTable
* _pNewTable
,sal_Int32 _nPos
)
2517 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::copyData" );
2518 sal_Int32 nPos
= _nPos
+ 1; // +1 because we always have the bookmark clumn as well
2519 OValueRefRow aRow
= new OValueRefVector(m_pColumns
->getCount());
2520 OValueRefRow aInsertRow
;
2523 aInsertRow
= new OValueRefVector(_pNewTable
->m_pColumns
->getCount());
2524 ::std::for_each(aInsertRow
->get().begin(),aInsertRow
->get().end(),TSetRefBound(sal_True
));
2529 // we only have to bind the values which we need to copy into the new table
2530 ::std::for_each(aRow
->get().begin(),aRow
->get().end(),TSetRefBound(sal_True
));
2531 if(_nPos
&& (_nPos
< (sal_Int32
)aRow
->get().size()))
2532 (aRow
->get())[nPos
]->setBound(sal_False
);
2535 sal_Bool bOk
= sal_True
;
2537 OValueRefVector::Vector::iterator aIter
;
2538 for(sal_uInt32 nRowPos
= 0; nRowPos
< m_aHeader
.db_anz
;++nRowPos
)
2540 bOk
= seekRow( IResultSetHelper::BOOKMARK
, nRowPos
+1, nCurPos
);
2543 bOk
= fetchRow( aRow
, *m_aColumns
, sal_True
, sal_True
);
2544 if ( bOk
&& !aRow
->isDeleted() ) // copy only not deleted rows
2546 // special handling when pos == 0 then we don't have to distinguish between the two rows
2549 aIter
= aRow
->get().begin()+1;
2550 sal_Int32 nCount
= 1;
2551 for(OValueRefVector::Vector::iterator aInsertIter
= aInsertRow
->get().begin()+1; aIter
!= aRow
->get().end() && aInsertIter
!= aInsertRow
->get().end();++aIter
,++nCount
)
2555 (*aInsertIter
)->setValue( (*aIter
)->getValue() );
2560 bOk
= _pNewTable
->InsertRow(*aInsertRow
,sal_True
,_pNewTable
->m_pColumns
);
2561 OSL_ENSURE(bOk
,"Row could not be inserted!");
2564 OSL_ENSURE(bOk
,"Row could not be fetched!");
2570 } // for(sal_uInt32 nRowPos = 0; nRowPos < m_aHeader.db_anz;++nRowPos)
2572 // -----------------------------------------------------------------------------
2573 void ODbaseTable::throwInvalidDbaseFormat()
2575 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::throwInvalidDbaseFormat" );
2579 const OUString
sError( getConnection()->getResources().getResourceStringWithSubstitution(
2580 STR_INVALID_DBASE_FILE
,
2581 "$filename$", getEntry(m_pConnection
,m_Name
)
2583 ::dbtools::throwGenericSQLException( sError
, *this );
2585 // -----------------------------------------------------------------------------
2586 void ODbaseTable::refreshHeader()
2588 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::refreshHeader" );
2589 if ( m_aHeader
.db_anz
== 0 )
2592 //------------------------------------------------------------------
2593 sal_Bool
ODbaseTable::seekRow(IResultSetHelper::Movement eCursorPosition
, sal_Int32 nOffset
, sal_Int32
& nCurPos
)
2595 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::seekRow" );
2596 // ----------------------------------------------------------
2597 // prepare positioning:
2598 OSL_ENSURE(m_pFileStream
,"ODbaseTable::seekRow: FileStream is NULL!");
2600 sal_uInt32 nNumberOfRecords
= (sal_uInt32
)m_aHeader
.db_anz
;
2601 sal_uInt32 nTempPos
= m_nFilePos
;
2602 m_nFilePos
= nCurPos
;
2604 switch(eCursorPosition
)
2606 case IResultSetHelper::NEXT
:
2609 case IResultSetHelper::PRIOR
:
2613 case IResultSetHelper::FIRST
:
2616 case IResultSetHelper::LAST
:
2617 m_nFilePos
= nNumberOfRecords
;
2619 case IResultSetHelper::RELATIVE
:
2620 m_nFilePos
= (((sal_Int32
)m_nFilePos
) + nOffset
< 0) ? 0L
2621 : (sal_uInt32
)(((sal_Int32
)m_nFilePos
) + nOffset
);
2623 case IResultSetHelper::ABSOLUTE
:
2624 case IResultSetHelper::BOOKMARK
:
2625 m_nFilePos
= (sal_uInt32
)nOffset
;
2629 if (m_nFilePos
> (sal_Int32
)nNumberOfRecords
)
2630 m_nFilePos
= (sal_Int32
)nNumberOfRecords
+ 1;
2632 if (m_nFilePos
== 0 || m_nFilePos
== (sal_Int32
)nNumberOfRecords
+ 1)
2636 sal_uInt16 nEntryLen
= m_aHeader
.db_slng
;
2638 OSL_ENSURE(m_nFilePos
>= 1,"SdbDBFCursor::FileFetchRow: ungueltige Record-Position");
2639 sal_Int32 nPos
= m_aHeader
.db_kopf
+ (sal_Int32
)(m_nFilePos
-1) * nEntryLen
;
2641 m_pFileStream
->Seek(nPos
);
2642 if (m_pFileStream
->GetError() != ERRCODE_NONE
)
2645 m_pFileStream
->Read((char*)m_pBuffer
, nEntryLen
);
2646 if (m_pFileStream
->GetError() != ERRCODE_NONE
)
2652 switch(eCursorPosition
)
2654 case IResultSetHelper::PRIOR
:
2655 case IResultSetHelper::FIRST
:
2658 case IResultSetHelper::LAST
:
2659 case IResultSetHelper::NEXT
:
2660 case IResultSetHelper::ABSOLUTE
:
2661 case IResultSetHelper::RELATIVE
:
2663 m_nFilePos
= nNumberOfRecords
+ 1;
2664 else if (nOffset
< 0)
2667 case IResultSetHelper::BOOKMARK
:
2668 m_nFilePos
= nTempPos
; // last position
2673 nCurPos
= m_nFilePos
;
2676 // -----------------------------------------------------------------------------
2677 sal_Bool
ODbaseTable::ReadMemo(sal_uIntPtr nBlockNo
, ORowSetValue
& aVariable
)
2679 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::ReadMemo" );
2680 bool bIsText
= true;
2682 m_pMemoStream
->Seek(nBlockNo
* m_aMemoHeader
.db_size
);
2683 switch (m_aMemoHeader
.db_typ
)
2685 case MemodBaseIII
: // dBase III-Memofield, ends with Ctrl-Z
2687 const char cEOF
= (char) DBF_EOL
;
2688 OStringBuffer aBStr
;
2689 static char aBuf
[514];
2690 aBuf
[512] = 0; // avoid random value
2691 sal_Bool bReady
= sal_False
;
2695 m_pMemoStream
->Read(&aBuf
,512);
2698 while (aBuf
[i
] != cEOF
&& ++i
< 512)
2700 bReady
= aBuf
[i
] == cEOF
;
2705 } while (!bReady
&& !m_pMemoStream
->IsEof());
2707 aVariable
= OStringToOUString(aBStr
.makeStringAndClear(),
2712 case MemodBaseIV
: // dBase IV-Memofield with length
2715 m_pMemoStream
->Read(sHeader
,4);
2716 // Foxpro stores text and binary data
2717 if (m_aMemoHeader
.db_typ
== MemoFoxPro
)
2719 bIsText
= sHeader
[3] != 0;
2721 else if (((sal_uInt8
)sHeader
[0]) != 0xFF || ((sal_uInt8
)sHeader
[1]) != 0xFF || ((sal_uInt8
)sHeader
[2]) != 0x08)
2726 sal_uInt32
nLength(0);
2727 (*m_pMemoStream
) >> nLength
;
2729 if (m_aMemoHeader
.db_typ
== MemodBaseIV
)
2736 OStringBuffer
aBuffer(read_uInt8s_ToOString(*m_pMemoStream
, nLength
));
2737 //pad it out with ' ' to expected length on short read
2738 sal_Int32 nRequested
= sal::static_int_cast
<sal_Int32
>(nLength
);
2739 comphelper::string::padToLength(aBuffer
, nRequested
, ' ');
2740 aVariable
= OStringToOUString(aBuffer
.makeStringAndClear(), m_eEncoding
);
2744 ::com::sun::star::uno::Sequence
< sal_Int8
> aData(nLength
);
2745 m_pMemoStream
->Read(aData
.getArray(),nLength
);
2753 // -----------------------------------------------------------------------------
2754 void ODbaseTable::AllocBuffer()
2756 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::AllocBuffer" );
2757 sal_uInt16 nSize
= m_aHeader
.db_slng
;
2758 OSL_ENSURE(nSize
> 0, "Size too small");
2760 if (m_nBufferSize
!= nSize
)
2766 // if there is no buffer available: allocate:
2767 if (m_pBuffer
== NULL
&& nSize
> 0)
2769 m_nBufferSize
= nSize
;
2770 m_pBuffer
= new sal_uInt8
[m_nBufferSize
+1];
2773 // -----------------------------------------------------------------------------
2774 sal_Bool
ODbaseTable::WriteBuffer()
2776 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::WriteBuffer" );
2777 OSL_ENSURE(m_nFilePos
>= 1,"SdbDBFCursor::FileFetchRow: ungueltige Record-Position");
2779 // postion on desired record:
2780 long nPos
= m_aHeader
.db_kopf
+ (long)(m_nFilePos
-1) * m_aHeader
.db_slng
;
2781 m_pFileStream
->Seek(nPos
);
2782 return m_pFileStream
->Write((char*) m_pBuffer
, m_aHeader
.db_slng
) > 0;
2784 // -----------------------------------------------------------------------------
2785 sal_Int32
ODbaseTable::getCurrentLastPos() const
2787 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getCurrentLastPos" );
2788 return m_aHeader
.db_anz
;
2791 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */