fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / connectivity / source / drivers / dbase / DTable.cxx
blob99819f38510683d843b472b84338c96cacb44120
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
57 #include <algorithm>
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
79 #define DBF_EOL 0x1A
81 namespace
83 sal_Int32 lcl_getFileSize(SvStream& _rStream)
85 sal_Int32 nFileSize = 0;
86 _rStream.Seek(STREAM_SEEK_TO_END);
87 _rStream.SeekRel(-1);
88 char cEOL;
89 _rStream >> cEOL;
90 nFileSize = _rStream.Tell();
91 if ( cEOL == DBF_EOL )
92 nFileSize -= 1;
93 return nFileSize;
95 /**
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;
101 // weird: months fix
102 if (aDateTime.Month > 12)
104 aDateTime.Month--;
105 sal_uInt16 delta = _aDateTime.Month / 12;
106 aDateTime.Year += delta;
107 aDateTime.Month -= delta * 12;
108 aDateTime.Month++;
111 _nJulianTime = ((aDateTime.Hours*3600000)+(aDateTime.Minutes*60000)+(aDateTime.Seconds*1000)+(aDateTime.NanoSeconds/1000000));
112 /* conversion factors */
113 sal_uInt16 iy0;
114 sal_uInt16 im0;
115 if ( aDateTime.Month <= 2 )
117 iy0 = aDateTime.Year - 1;
118 im0 = aDateTime.Month + 12;
120 else
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 )
134 else
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 */
144 _nJulianDate += ib;
148 calculates date time from the Julian Date
150 void lcl_CalDate(sal_Int32 _nJulianDate,sal_Int32 _nJulianTime,com::sun::star::util::DateTime& _rDateTime)
152 if ( _nJulianDate )
154 sal_Int32 ialp;
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 )));
166 if ( ke > 13 )
167 _rDateTime.Month = static_cast<sal_uInt16>(ke - 13);
168 else
169 _rDateTime.Month = static_cast<sal_uInt16>(ke - 1);
170 if ( (_rDateTime.Month == 2) && (_rDateTime.Day > 28) )
171 _rDateTime.Day = 29;
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);
176 else
177 _rDateTime.Year = static_cast<sal_uInt16>(kc - 4715);
180 if ( _nJulianTime )
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!");
198 if(!m_pFileStream)
199 return;
200 m_pFileStream->RefreshBuffer(); // Make sure, that the header information actually is read again
201 m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
203 sal_uInt8 nType=0;
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
226 // no dbase file
227 throwInvalidDbaseFormat();
229 else
231 // Consistency check of the header:
232 m_aHeader.db_typ = (DBFType)nType;
233 switch (m_aHeader.db_typ)
235 case dBaseIII:
236 case dBaseIV:
237 case dBaseV:
238 case VisualFoxPro:
239 case VisualFoxProAuto:
240 case dBaseFS:
241 case dBaseFSMemo:
242 case dBaseIVMemoSQL:
243 case dBaseIIIMemo:
244 case FoxProMemo:
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
279 default:
280 // Default Encoding
281 m_eEncoding = RTL_TEXTENCODING_IBM_850;
282 break;
285 break;
286 case dBaseIVMemo:
287 m_pFileStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
288 break;
289 default:
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);
303 if(!m_aColumns.is())
304 m_aColumns = new OSQLColumns();
305 else
306 m_aColumns->get().clear();
308 m_aTypes.clear();
309 m_aPrecisions.clear();
310 m_aScales.clear();
312 // Number of fields:
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");
323 OUString aTypeName;
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;
327 sal_Int32 i = 0;
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.
333 break;
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;
340 sal_Int32 eType;
341 sal_Bool bIsCurrency = sal_False;
343 char cType[2];
344 cType[0] = aDBFColumn.db_typ;
345 cType[1] = 0;
346 aTypeName = OUString::createFromAscii(cType);
347 OSL_TRACE("column type: %c",aDBFColumn.db_typ);
349 switch (aDBFColumn.db_typ)
351 case 'C':
352 eType = DataType::VARCHAR;
353 aTypeName = "VARCHAR";
354 break;
355 case 'F':
356 case 'N':
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 ....
366 break;
367 case 'L':
368 eType = DataType::BIT;
369 aTypeName = "BOOLEAN";
370 break;
371 case 'Y':
372 bIsCurrency = sal_True;
373 eType = DataType::DOUBLE;
374 aTypeName = "DOUBLE";
375 break;
376 case 'D':
377 eType = DataType::DATE;
378 aTypeName = "DATE";
379 break;
380 case 'T':
381 eType = DataType::TIMESTAMP;
382 aTypeName = "TIMESTAMP";
383 break;
384 case 'I':
385 eType = DataType::INTEGER;
386 aTypeName = "INTEGER";
387 break;
388 case 'M':
389 if ( bFoxPro && ( aDBFColumn.db_frei2[0] & 0x04 ) == 0x04 )
391 eType = DataType::LONGVARBINARY;
392 aTypeName = "LONGVARBINARY";
394 else
396 aTypeName = "LONGVARCHAR";
397 eType = DataType::LONGVARCHAR;
399 nPrecision = 2147483647;
400 break;
401 case 'P':
402 aTypeName = "LONGVARBINARY";
403 eType = DataType::LONGVARBINARY;
404 nPrecision = 2147483647;
405 break;
406 case '0':
407 case 'B':
408 if ( m_aHeader.db_typ == VisualFoxPro || m_aHeader.db_typ == VisualFoxProAuto )
410 aTypeName = "DOUBLE";
411 eType = DataType::DOUBLE;
413 else
415 aTypeName = "LONGVARBINARY";
416 eType = DataType::LONGVARBINARY;
417 nPrecision = 2147483647;
419 break;
420 default:
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,
429 aTypeName,
430 OUString(),
431 OUString(),
432 ColumnValue::NULLABLE,
433 nPrecision,
434 aDBFColumn.db_dez,
435 eType,
436 sal_False,
437 bIsRowVersion,
438 bIsCurrency,
439 bCase,
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)
448 ,m_pMemoStream(NULL)
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,
467 _Type,
468 _Description,
469 _SchemaName,
470 _CatalogName)
471 ,m_pMemoStream(NULL)
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));
491 INetURLObject aURL;
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);
507 if(m_pFileStream)
509 readHeader();
510 if (HasMemoFields())
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");
517 else
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);
529 if (m_pMemoStream)
530 ReadMemoHeader();
532 fillColumns();
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);
544 if (m_pMemoStream)
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);
558 AllocBuffer();
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
573 case dBaseIVMemo:
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
582 char sHeader[4];
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;
588 else
589 m_aMemoHeader.db_typ = MemodBaseIV;
591 else
593 m_aMemoHeader.db_typ = MemodBaseIII;
594 m_aMemoHeader.db_size = 512;
596 break;
597 case VisualFoxPro:
598 case VisualFoxProAuto:
599 case FoxProMemo:
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;
604 break;
605 default:
606 OSL_FAIL( "ODbaseTable::ReadMemoHeader: unsupported memo type!" );
607 break;
609 return sal_True;
611 // -------------------------------------------------------------------------
612 String ODbaseTable::getEntry(OConnection* _pConnection,const OUString& _sName )
614 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getEntry" );
615 OUString sURL;
618 Reference< XResultSet > xDir = _pConnection->getDir()->getStaticResultSet();
619 Reference< XRow> xRow(xDir,UNO_QUERY);
620 OUString sName;
621 OUString sExt;
622 INetURLObject aURL;
623 static const OUString s_sSeparator("/");
624 xDir->beforeFirst();
625 while(xDir->next())
627 sName = xRow->getString(1);
628 aURL.SetSmartProtocol(INET_PROT_FILE);
629 String sUrl = _pConnection->getURL() + s_sSeparator + sName;
630 aURL.SetSmartURL( sUrl );
632 // cut the extension
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();
643 break;
647 xDir->beforeFirst(); // move back to before first record
649 catch(const Exception&)
651 OSL_ASSERT(0);
653 return sURL;
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());
667 if(m_pColumns)
668 m_pColumns->reFill(aVector);
669 else
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))
679 INetURLObject aURL;
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();
686 OString aKeyName;
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
711 if(m_pIndexes)
712 m_pIndexes->reFill(aVector);
713 else
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);
723 m_aColumns = NULL;
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))
754 return Any();
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;
765 if (! pId)
767 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
768 if (! pId)
770 static ::cppu::OImplementationId aId;
771 pId = &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" );
790 // Read the data
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;
799 if (!bRetrieveData)
800 return sal_True;
802 sal_Size nByteOffset = 1;
803 // Fields:
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:
810 sal_Int32 nLen = 0;
811 sal_Int32 nType = 0;
812 if(_bUseTableDefs)
814 nLen = m_aPrecisions[i-1];
815 nType = m_aTypes[i-1];
817 else
819 (*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nLen;
820 (*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
822 switch(nType)
824 case DataType::INTEGER:
825 case DataType::DOUBLE:
826 case DataType::TIMESTAMP:
827 case DataType::DATE:
828 case DataType::BIT:
829 case DataType::LONGVARCHAR:
830 case DataType::LONGVARBINARY:
831 nLen = m_aRealFieldLengths[i-1];
832 break;
833 case DataType::DECIMAL:
834 if(_bUseTableDefs)
835 nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,m_aScales[i-1]);
836 else
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:
842 nByteOffset += nLen;
843 continue;
846 // Is the variable bound?
847 if ( !(_rRow->get())[i]->isBound() )
849 // No - next field.
850 nByteOffset += nLen;
851 OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
852 continue;
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)
864 if (pData[k] != ' ')
865 // Record last non-empty position.
866 nLastPos = k;
868 if (nLastPos < 0)
870 // Empty string. Skip it.
871 (_rRow->get())[i]->setNull();
873 else
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();
888 else
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 )
903 double d = 0.0;
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]));
911 else
912 d = (double)(nValue);
914 else
916 memcpy(&d, pData, nLen);
919 *(_rRow->get())[i] = d;
921 else
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')
928 pData[k] = ' ';
930 if (pData[k] != ' ')
932 if (nPos1 < 0)
933 // first non-empty char position.
934 nPos1 = k;
936 // last non-empty char position.
937 nPos2 = k;
941 if (nPos1 < 0)
943 // Empty string. Skip it.
944 nByteOffset += nLen;
945 (_rRow->get())[i]->setNull(); // no values -> done
946 continue;
949 OUString aStr = OUString::intern(pData+nPos1, nPos2-nPos1+1, m_eEncoding);
951 switch (nType)
953 case DataType::DATE:
955 if (aStr.getLength() != nLen)
957 (_rRow->get())[i]->setNull();
958 break;
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;
967 break;
968 case DataType::DECIMAL:
969 *(_rRow->get())[i] = ORowSetValue(aStr);
970 break;
971 case DataType::BIT:
973 sal_Bool b;
974 switch (* ((const char *)pData))
976 case 'T':
977 case 'Y':
978 case 'J': b = sal_True; break;
979 default: b = sal_False; break;
981 *(_rRow->get())[i] = b;
983 break;
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()) )
992 break;
994 else
995 (_rRow->get())[i]->setNull();
996 } break;
997 default:
998 OSL_FAIL("Falscher Type");
1000 (_rRow->get())[i]->setTypeKind(nType);
1003 nByteOffset += nLen;
1004 OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
1006 return sal_True;
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(
1032 STR_SQL_NAME_ERROR,
1033 "$name$", m_Name
1034 ) );
1035 ::dbtools::throwGenericSQLException( sError, *this );
1038 INetURLObject aURL;
1039 aURL.SetSmartProtocol(INET_PROT_FILE);
1040 String aName = getEntry(m_pConnection,m_Name);
1041 if(!aName.Len())
1043 OUString aIdent = m_pConnection->getContent()->getIdentifier()->getContentIdentifier();
1044 if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) )
1045 aIdent += "/";
1046 aIdent += m_Name;
1047 aName = aIdent.getStr();
1049 aURL.SetURL(aName);
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))
1064 return sal_False;
1066 delete pFileStream;
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);
1077 FileClose();
1079 if (!bOk)
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
1089 return sal_False;
1092 if (bMemoFile)
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,
1119 "$name$", aName
1120 ) );
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 ) );
1129 return sal_False;
1131 m_aHeader.db_typ = dBaseIIIMemo;
1133 else
1134 m_aHeader.db_typ = dBaseIII;
1136 return sal_True;
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
1145 DropImpl();
1147 catch(const Exception&)
1151 const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
1152 _nErrorId,
1153 "$columnname$", _sColumnName
1154 ) );
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 );
1167 if (!m_pFileStream)
1168 return sal_False;
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
1191 break;
1192 } // switch (getINT32(xCol->getPropertyValue(sPropType)))
1195 catch ( const Exception& e )
1197 (void)e;
1201 // we have to drop the file because it is corrupted now
1202 DropImpl();
1204 catch(const Exception&) { }
1205 throw;
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();
1226 OUString aName;
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!");
1239 char cTyp( 'C' );
1241 xCol->getPropertyValue(sPropName) >>= aName;
1243 OString aCol;
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:
1263 cTyp = 'C';
1264 break;
1265 case DataType::DOUBLE:
1266 if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency will be treated separately
1267 cTyp = 'Y';
1268 else
1269 cTyp = 'B';
1270 break;
1271 case DataType::INTEGER:
1272 cTyp = 'I';
1273 break;
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
1281 break;
1282 case DataType::TIMESTAMP:
1283 cTyp = 'T';
1284 break;
1285 case DataType::DATE:
1286 cTyp = 'D';
1287 break;
1288 case DataType::BIT:
1289 cTyp = 'L';
1290 break;
1291 case DataType::LONGVARBINARY:
1292 bBinary = true;
1293 // run through
1294 case DataType::LONGVARCHAR:
1295 cTyp = 'M';
1296 break;
1297 default:
1299 throwInvalidColumnType(STR_INVALID_COLUMN_TYPE, aName);
1303 (*m_pFileStream) << cTyp;
1304 if ( nDbaseType == VisualFoxPro )
1305 (*m_pFileStream) << sal_uInt32(nRecLength-1);
1306 else
1307 m_pFileStream->Write(aBuffer, 4);
1309 switch(cTyp)
1311 case 'C':
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
1320 break;
1321 case 'F':
1322 case 'N':
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;
1333 nRecLength += 10;
1335 else
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;
1343 break;
1344 case 'L':
1345 (*m_pFileStream) << (sal_uInt8)1;
1346 (*m_pFileStream) << (sal_uInt8)0;
1347 ++nRecLength;
1348 break;
1349 case 'I':
1350 (*m_pFileStream) << (sal_uInt8)4;
1351 (*m_pFileStream) << (sal_uInt8)0;
1352 nRecLength += 4;
1353 break;
1354 case 'Y':
1355 case 'B':
1356 case 'T':
1357 case 'D':
1358 (*m_pFileStream) << (sal_uInt8)8;
1359 (*m_pFileStream) << (sal_uInt8)0;
1360 nRecLength += 8;
1361 break;
1362 case 'M':
1363 bCreateMemo = sal_True;
1364 (*m_pFileStream) << (sal_uInt8)10;
1365 (*m_pFileStream) << (sal_uInt8)0;
1366 nRecLength += 10;
1367 if ( bBinary )
1368 aBuffer[0] = 0x06;
1369 break;
1370 default:
1371 throwInvalidColumnType(STR_INVALID_COLUMN_TYPE, aName);
1373 m_pFileStream->Write(aBuffer, 14);
1374 aBuffer[0] = 0x00;
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
1382 if (bCreateMemo)
1384 m_pFileStream->Seek(0L);
1385 if (nDbaseType == VisualFoxPro)
1386 (*m_pFileStream) << (sal_uInt8) FoxProMemo;
1387 else
1388 (*m_pFileStream) << (sal_uInt8) dBaseIIIMemo;
1389 } // if (bCreateMemo)
1391 catch ( const Exception& e )
1393 (void)e;
1397 // we have to drop the file because it is corrupted now
1398 DropImpl();
1400 catch(const Exception&) { }
1401 throw;
1403 return sal_True;
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);
1414 if (!m_pMemoStream)
1415 return sal_False;
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;
1425 return sal_True;
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" );
1431 INetURLObject aURL;
1432 aURL.SetURL(_sUrl);
1434 sal_Bool bDropped = ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::NO_DECODE));
1436 if(bDropped)
1438 if (_bHasMemoFields)
1439 { // delete the memo fields
1440 aURL.setExtension("dbt");
1441 bDropped = ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::NO_DECODE));
1444 if(bDropped)
1446 if(_pIndexes)
1450 sal_Int32 i = _pIndexes->getCount();
1451 while (i)
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 ....
1474 return bDropped;
1476 // -----------------------------------------------------------------------------
1477 sal_Bool ODbaseTable::DropImpl()
1479 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::DropImpl" );
1480 FileClose();
1482 if(!m_pIndexes)
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);
1486 if(!bDropped)
1487 {// we couldn't drop the table so we have to reopen it
1488 construct();
1489 if(m_pColumns)
1490 m_pColumns->refresh();
1492 return bDropped;
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
1500 AllocBuffer();
1501 memset(m_pBuffer, 0, m_aHeader.db_slng);
1502 m_pBuffer[0] = ' ';
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 );
1510 if ( bInsertRow )
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();
1522 if (!WriteBuffer())
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
1530 else
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!
1538 if (bFlush)
1539 m_pFileStream->Flush();
1541 // raise number if successfully
1542 m_aHeader.db_anz++;
1543 *rRow.get()[0] = m_nFilePos; // set bookmark
1544 m_nFilePos = nTempPos;
1547 else
1548 m_nFilePos = nTempPos;
1550 return bInsertRow;
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
1558 AllocBuffer();
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
1576 else
1578 m_pFileStream->Flush();
1580 return sal_True;
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))
1595 return sal_False;
1597 Reference<XPropertySet> xCol;
1598 OUString aColName;
1599 ::comphelper::UStringMixEqual aCase(isCaseSensitive());
1600 for (sal_uInt16 i = 0; i < m_pColumns->getCount(); i++)
1602 Reference<XPropertySet> xIndex = isUniqueByColumnName(i);
1603 if (xIndex.is())
1605 ::cppu::extractInterface(xCol,m_pColumns->getByIndex(i));
1606 OSL_ENSURE(xCol.is(),"ODbaseTable::DeleteRow column is null!");
1607 if(xCol.is())
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();
1617 sal_Int32 nPos = 1;
1618 for(;aIter != _rCols.get().end();++aIter,++nPos)
1620 if(aCase(getString((*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME))),aColName))
1621 break;
1623 if (aIter == _rCols.get().end())
1624 continue;
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();
1634 return sal_True;
1636 // -------------------------------------------------------------------------
1637 Reference<XPropertySet> ODbaseTable::isUniqueByColumnName(sal_Int32 _nColumnPos)
1639 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::isUniqueByColumnName" );
1640 if(!m_pIndexes)
1641 refreshIndexes();
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!");
1647 OUString sColName;
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))
1658 return xIndex;
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!");
1676 if ( !m_pBuffer )
1677 return sal_False;
1678 sal_Int32 nByteOffset = 1;
1680 // Update fields:
1681 Reference<XPropertySet> xCol;
1682 Reference<XPropertySet> xIndex;
1683 sal_uInt16 i;
1684 OUString aColName;
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)
1694 sal_Int32 nPos = 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))
1707 break;
1709 if (nPos >= _xCols->getCount())
1710 continue;
1713 ++nPos;
1714 xIndex = isUniqueByColumnName(i);
1715 aIndexedCols[i] = xIndex;
1716 if (xIndex.is())
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]))
1720 continue;
1721 else
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;
1736 xCol.clear();
1737 } // if ( !aColName.getLength() )
1738 const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
1739 STR_DUPLICATE_VALUE_IN_COLUMN
1740 ,"$columnname$", aColName
1741 ) );
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!");
1754 sal_Int32 nLen = 0;
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];
1763 else
1765 m_pColumns->getByIndex(i) >>= xCol;
1766 if ( xCol.is() )
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;
1775 switch (nType)
1777 case DataType::INTEGER:
1778 case DataType::DOUBLE:
1779 case DataType::TIMESTAMP:
1780 bSetZero = true;
1781 case DataType::LONGVARBINARY:
1782 case DataType::DATE:
1783 case DataType::BIT:
1784 case DataType::LONGVARCHAR:
1785 nLen = m_aRealFieldLengths[i];
1786 break;
1787 case DataType::DECIMAL:
1788 nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,nScale);
1789 break; // The sign and the comma
1790 default:
1791 break;
1793 } // switch (nType)
1795 sal_Int32 nPos = i;
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))
1806 break;
1808 if (nPos >= _xCols->getCount())
1810 nByteOffset += nLen;
1811 continue;
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;
1826 continue;
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!");
1834 // Update !!
1835 if (pOrgRow.is() && !thisColIsNull)
1836 pIndex->Update(m_nFilePos, *(pOrgRow->get())[nPos], thisColVal);
1837 else
1838 pIndex->Insert(m_nFilePos, thisColVal);
1841 char* pData = (char *)(m_pBuffer + nByteOffset);
1842 if (thisColIsNull)
1844 if ( bSetZero )
1845 memset(pData,0,nLen); // Clear to NULL char ('\0')
1846 else
1847 memset(pData,' ',nLen); // Clear to space/blank ('\0x20')
1848 nByteOffset += nLen;
1849 OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
1850 continue;
1855 switch (nType)
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);
1865 break;
1866 case DataType::DATE:
1868 ::com::sun::star::util::Date aDate;
1869 if(thisColVal.getTypeKind() == DataType::DOUBLE)
1870 aDate = ::dbtools::DBTypeConversion::toDate(thisColVal.getDouble());
1871 else
1872 aDate = thisColVal;
1873 char s[9];
1874 snprintf(s,
1875 sizeof(s),
1876 "%04d%02d%02d",
1877 (int)aDate.Year,
1878 (int)aDate.Month,
1879 (int)aDate.Day);
1881 // Exactly 8 bytes to copy:
1882 strncpy(pData,s,sizeof s - 1);
1883 } break;
1884 case DataType::INTEGER:
1886 sal_Int32 nValue = thisColVal;
1887 memcpy(pData,&nValue,nLen);
1889 break;
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;
1898 if ( m_aScales[i] )
1899 nValue = (sal_Int64)(d * pow(10.0,(int)m_aScales[i]));
1900 else
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
1904 else
1905 memcpy(pData,&d,nLen);
1907 break;
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);
1925 else
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
1939 ) );
1940 ::dbtools::throwGenericSQLException( sError, *this );
1942 } break;
1943 case DataType::BIT:
1944 *pData = thisColVal.getBool() ? 'T' : 'F';
1945 break;
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))
1957 break;
1959 OString aBlock(OString::number(nBlockNo));
1960 //align aBlock at the right of a nLen sequence, fill to the left with '0'
1961 OStringBuffer aStr;
1962 comphelper::string::padToLength(aStr, nLen - aBlock.getLength(), '0');
1963 aStr.append(aBlock);
1965 // Copy characters:
1966 memcpy(pData, aStr.getStr(), nLen);
1967 } break;
1968 default:
1970 memset(pData,' ',nLen); // Clear to NULL
1972 OUString sStringToWrite( thisColVal.getString() );
1974 // convert the string, using the connection's encoding
1975 OString sEncoded;
1977 DBTypeConversion::convertUnicodeStringToLength( sStringToWrite, sEncoded, nLen, m_eEncoding );
1978 memcpy( pData, sEncoded.getStr(), sEncoded.getLength() );
1981 break;
1984 catch( const SQLException& )
1986 throw;
1988 catch ( const Exception& )
1990 m_pColumns->getByIndex(i) >>= xCol;
1991 OSL_ENSURE( xCol.is(), "ODbaseTable::UpdateBuffer column is null!" );
1992 if ( xCol.is() )
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
1998 ) );
1999 ::dbtools::throwGenericSQLException( sError, *this );
2001 // And more ...
2002 nByteOffset += nLen;
2003 OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
2005 return sal_True;
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;
2014 OString aStr;
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;
2018 if ( bBinary )
2020 aValue = aVariable.getSequence();
2021 nSize = aValue.getLength();
2023 else
2025 nSize = DBTypeConversion::convertUnicodeString( aVariable.getString(), aStr, m_eEncoding );
2028 // append or overwrite
2029 sal_Bool bAppend = rBlockNr == 0;
2031 if (!bAppend)
2033 switch (m_aMemoHeader.db_typ)
2035 case MemodBaseIII: // dBase III-Memofield, ends with 2 * Ctrl-Z
2036 bAppend = nSize > (512 - 2);
2037 break;
2038 case MemoFoxPro:
2039 case MemodBaseIV: // dBase IV-Memofield with length
2041 char sHeader[4];
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];
2052 else
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;
2066 if (bAppend)
2068 sal_uIntPtr nStreamSize = m_pMemoStream->Seek(STREAM_SEEK_TO_END);
2069 // fill last block
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);
2075 else
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;
2085 nSize++;
2086 m_pMemoStream->Write( aStr.getStr(), aStr.getLength() );
2087 (*m_pMemoStream) << cEOF << cEOF;
2088 } break;
2089 case MemoFoxPro:
2090 case MemodBaseIV: // dBase IV-Memofeld with length
2092 if ( MemodBaseIV == m_aMemoHeader.db_typ )
2093 (*m_pMemoStream) << (sal_uInt8)0xFF
2094 << (sal_uInt8)0xFF
2095 << (sal_uInt8)0x08;
2096 else
2097 (*m_pMemoStream) << (sal_uInt8)0x00
2098 << (sal_uInt8)0x00
2099 << (sal_uInt8)0x00;
2101 sal_uInt32 nWriteSize = nSize;
2102 if (m_aMemoHeader.db_typ == MemoFoxPro)
2104 if ( bBinary )
2105 (*m_pMemoStream) << (sal_uInt8) 0x00; // Picture
2106 else
2107 (*m_pMemoStream) << (sal_uInt8) 0x01; // Memo
2108 for (int i = 4; i > 0; nWriteSize >>= 8)
2109 nHeader[--i] = (sal_uInt8) (nWriteSize % 256);
2111 else
2113 (*m_pMemoStream) << (sal_uInt8) 0x00;
2114 nWriteSize += 8;
2115 for (int i = 0; i < 4; nWriteSize >>= 8)
2116 nHeader[i++] = (sal_uInt8) (nWriteSize % 256);
2119 m_pMemoStream->Write(nHeader,4);
2120 if ( bBinary )
2121 m_pMemoStream->Write( aValue.getConstArray(), aValue.getLength() );
2122 else
2123 m_pMemoStream->Write( aStr.getStr(), aStr.getLength() );
2124 m_pMemoStream->Flush();
2129 // Write the new block number
2130 if (bAppend)
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();
2140 return sal_True;
2143 // -----------------------------------------------------------------------------
2144 // XAlterTable
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;
2186 if(xOldColumn.is())
2187 xCopyColumn = xOldColumn->createDataDescriptor();
2188 else
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
2204 sal_Int32 i=0;
2205 for(;i < index;++i)
2207 Reference<XPropertySet> xProp;
2208 m_pColumns->getByIndex(i) >>= xProp;
2209 Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
2210 Reference<XPropertySet> xCpy;
2211 if(xColumn.is())
2212 xCpy = xColumn->createDataDescriptor();
2213 else
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;
2227 if(xColumn.is())
2228 xCpy = xColumn->createDataDescriptor();
2229 else
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)))
2241 ) );
2242 ::dbtools::throwGenericSQLException( sError, *this );
2245 pNewTable->construct();
2247 // copy the data
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
2256 pNewTable = NULL;
2257 ::comphelper::disposeComponent(xHoldTable);
2259 else
2261 pNewTable = NULL;
2263 FileClose();
2264 construct();
2265 if(m_pColumns)
2266 m_pColumns->refresh();
2269 catch(const SQLException&)
2271 throw;
2273 catch(const Exception&)
2275 OSL_FAIL("ODbaseTable::alterColumn: Exception occurred!");
2276 throw;
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);
2299 construct();
2300 if(m_pColumns)
2301 m_pColumns->refresh();
2303 namespace
2305 void renameFile(OConnection* _pConenction,const OUString& oldName,
2306 const OUString& newName,const String& _sExtension)
2308 String aName = ODbaseTable::getEntry(_pConenction,oldName);
2309 if(!aName.Len())
2311 OUString aIdent = _pConenction->getContent()->getIdentifier()->getContentIdentifier();
2312 if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) )
2313 aIdent += OUString("/");
2314 aIdent += oldName;
2315 aName = aIdent;
2317 INetURLObject aURL;
2318 aURL.SetURL(aName);
2320 aURL.setExtension( _sExtension );
2321 OUString sNewName(newName);
2322 sNewName += ".";
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())
2336 throw Exception();
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);
2350 FileClose();
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;
2379 if(xColumn.is())
2380 xCpy = xColumn->createDataDescriptor();
2381 else
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)))
2400 ) );
2401 ::dbtools::throwGenericSQLException( sError, *this );
2404 sal_Bool bAlreadyDroped = sal_False;
2407 pNewTable->construct();
2408 // copy the data
2409 copyData(pNewTable,pNewTable->m_pColumns->getCount());
2410 // drop the old table
2411 if(DropImpl())
2413 bAlreadyDroped = sal_True;
2414 pNewTable->renameImpl(m_Name);
2415 // release the temp file
2417 xHold = pNewTable = NULL;
2419 FileClose();
2420 construct();
2421 if(m_pColumns)
2422 m_pColumns->refresh();
2424 catch(const SQLException&)
2426 // here we know that the old table wasn't droped before
2427 if(!bAlreadyDroped)
2428 xHold = pNewTable = NULL;
2430 throw;
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)
2448 if(_nPos != i)
2450 Reference<XPropertySet> xProp;
2451 m_pColumns->getByIndex(i) >>= xProp;
2452 Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
2453 Reference<XPropertySet> xCpy;
2454 if(xColumn.is())
2455 xCpy = xColumn->createDataDescriptor();
2456 else
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)
2473 ) );
2474 ::dbtools::throwGenericSQLException( sError, *this );
2476 pNewTable->construct();
2477 // copy the data
2478 copyData(pNewTable,_nPos);
2479 // drop the old table
2480 if(DropImpl())
2481 pNewTable->renameImpl(m_Name);
2482 // release the temp file
2484 xHold = pNewTable = NULL;
2486 FileClose();
2487 construct();
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) )
2495 aIdent += "/";
2496 String sTempName(aIdent);
2497 String sExt;
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);
2506 INetURLObject aURL;
2507 aURL.SetSmartProtocol(INET_PROT_FILE);
2508 aURL.SetURL(aTempFile.GetURL());
2510 String sNewName(aURL.getName());
2511 sNewName.Erase(sNewName.Len() - sExt.Len());
2512 return sNewName;
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;
2521 if(_nPos)
2523 aInsertRow = new OValueRefVector(_pNewTable->m_pColumns->getCount());
2524 ::std::for_each(aInsertRow->get().begin(),aInsertRow->get().end(),TSetRefBound(sal_True));
2526 else
2527 aInsertRow = aRow;
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;
2536 sal_Int32 nCurPos;
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 );
2541 if ( bOk )
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
2547 if(_nPos)
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)
2553 if(nPos != nCount)
2555 (*aInsertIter)->setValue( (*aIter)->getValue() );
2556 ++aInsertIter;
2560 bOk = _pNewTable->InsertRow(*aInsertRow,sal_True,_pNewTable->m_pColumns);
2561 OSL_ENSURE(bOk,"Row could not be inserted!");
2563 else
2564 OSL_ENSURE(bOk,"Row could not be fetched!");
2566 else
2568 OSL_ASSERT(0);
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" );
2576 FileClose();
2577 // no dbase file
2579 const OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
2580 STR_INVALID_DBASE_FILE,
2581 "$filename$", getEntry(m_pConnection,m_Name)
2582 ) );
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 )
2590 readHeader();
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:
2607 ++m_nFilePos;
2608 break;
2609 case IResultSetHelper::PRIOR:
2610 if (m_nFilePos > 0)
2611 --m_nFilePos;
2612 break;
2613 case IResultSetHelper::FIRST:
2614 m_nFilePos = 1;
2615 break;
2616 case IResultSetHelper::LAST:
2617 m_nFilePos = nNumberOfRecords;
2618 break;
2619 case IResultSetHelper::RELATIVE:
2620 m_nFilePos = (((sal_Int32)m_nFilePos) + nOffset < 0) ? 0L
2621 : (sal_uInt32)(((sal_Int32)m_nFilePos) + nOffset);
2622 break;
2623 case IResultSetHelper::ABSOLUTE:
2624 case IResultSetHelper::BOOKMARK:
2625 m_nFilePos = (sal_uInt32)nOffset;
2626 break;
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)
2633 goto Error;
2634 else
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)
2643 goto Error;
2645 m_pFileStream->Read((char*)m_pBuffer, nEntryLen);
2646 if (m_pFileStream->GetError() != ERRCODE_NONE)
2647 goto Error;
2649 goto End;
2651 Error:
2652 switch(eCursorPosition)
2654 case IResultSetHelper::PRIOR:
2655 case IResultSetHelper::FIRST:
2656 m_nFilePos = 0;
2657 break;
2658 case IResultSetHelper::LAST:
2659 case IResultSetHelper::NEXT:
2660 case IResultSetHelper::ABSOLUTE:
2661 case IResultSetHelper::RELATIVE:
2662 if (nOffset > 0)
2663 m_nFilePos = nNumberOfRecords + 1;
2664 else if (nOffset < 0)
2665 m_nFilePos = 0;
2666 break;
2667 case IResultSetHelper::BOOKMARK:
2668 m_nFilePos = nTempPos; // last position
2670 return sal_False;
2672 End:
2673 nCurPos = m_nFilePos;
2674 return sal_True;
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);
2697 sal_uInt16 i = 0;
2698 while (aBuf[i] != cEOF && ++i < 512)
2700 bReady = aBuf[i] == cEOF;
2702 aBuf[i] = 0;
2703 aBStr.append(aBuf);
2705 } while (!bReady && !m_pMemoStream->IsEof());
2707 aVariable = OStringToOUString(aBStr.makeStringAndClear(),
2708 m_eEncoding);
2710 } break;
2711 case MemoFoxPro:
2712 case MemodBaseIV: // dBase IV-Memofield with length
2714 char sHeader[4];
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)
2723 return sal_False;
2726 sal_uInt32 nLength(0);
2727 (*m_pMemoStream) >> nLength;
2729 if (m_aMemoHeader.db_typ == MemodBaseIV)
2730 nLength -= 8;
2732 if ( nLength )
2734 if ( bIsText )
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);
2741 } // if ( bIsText )
2742 else
2744 ::com::sun::star::uno::Sequence< sal_Int8 > aData(nLength);
2745 m_pMemoStream->Read(aData.getArray(),nLength);
2746 aVariable = aData;
2748 } // if ( nLength )
2751 return sal_True;
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)
2762 delete m_pBuffer;
2763 m_pBuffer = NULL;
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: */