1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_connectivity.hxx"
26 #include "dbase/DTable.hxx"
27 #include <com/sun/star/sdbc/ColumnValue.hpp>
28 #include <com/sun/star/sdbc/DataType.hpp>
29 #include <com/sun/star/ucb/XContentAccess.hpp>
30 #include <com/sun/star/sdbc/XRow.hpp>
31 #include <svl/converter.hxx>
32 #include "dbase/DConnection.hxx"
33 #include "dbase/DColumns.hxx"
34 #include <osl/thread.h>
35 #include <tools/config.hxx>
36 #include "dbase/DIndex.hxx"
37 #include "dbase/DIndexes.hxx"
38 //#include "file/FDriver.hxx"
39 #include <comphelper/sequence.hxx>
40 #include <svl/zforlist.hxx>
41 #include <unotools/syslocale.hxx>
42 #include <rtl/math.hxx>
43 #include <stdio.h> //sprintf
44 #include <ucbhelper/content.hxx>
45 #include <comphelper/extract.hxx>
46 #include <connectivity/dbexception.hxx>
47 #include <connectivity/dbconversion.hxx>
48 #include <com/sun/star/lang/DisposedException.hpp>
49 #include <comphelper/property.hxx>
50 //#include <unotools/calendarwrapper.hxx>
51 #include <unotools/tempfile.hxx>
52 #include <unotools/ucbhelper.hxx>
53 #include <comphelper/types.hxx>
54 #include <cppuhelper/exc_hlp.hxx>
55 #include "connectivity/PColumn.hxx"
56 #include "connectivity/dbtools.hxx"
57 #include "connectivity/FValue.hxx"
58 #include "connectivity/dbconversion.hxx"
59 #include "resource/dbase_res.hrc"
60 #include <rtl/logfile.hxx>
61
62 #include <algorithm>
63
64 using namespace ::comphelper;
65 using namespace connectivity;
66 using namespace connectivity::sdbcx;
67 using namespace connectivity::dbase;
68 using namespace connectivity::file;
69 using namespace ::ucbhelper;
70 using namespace ::utl;
71 using namespace ::cppu;
72 using namespace ::dbtools;
73 using namespace ::com::sun::star::uno;
74 using namespace ::com::sun::star::ucb;
75 using namespace ::com::sun::star::beans;
76 using namespace ::com::sun::star::sdbcx;
77 using namespace ::com::sun::star::sdbc;
78 using namespace ::com::sun::star::container;
79 using namespace ::com::sun::star::lang;
80 using namespace ::com::sun::star::i18n;
81
82 // stored as the Field Descriptor terminator
83 #define FIELD_DESCRIPTOR_TERMINATOR 0x0D
84 #define DBF_EOL 0x1A
85
86 namespace
87 {
lcl_getFileSize(SvStream & _rStream)88 sal_Int32 lcl_getFileSize(SvStream& _rStream)
89 {
90 sal_Int32 nFileSize = 0;
91 _rStream.Seek(STREAM_SEEK_TO_END);
92 _rStream.SeekRel(-1);
93 char cEOL;
94 _rStream >> cEOL;
95 nFileSize = _rStream.Tell();
96 if ( cEOL == DBF_EOL )
97 nFileSize -= 1;
98 return nFileSize;
99 }
100 /**
101 calculates the Julian date
102 */
lcl_CalcJulDate(sal_Int32 & _nJulianDate,sal_Int32 & _nJulianTime,const com::sun::star::util::DateTime _aDateTime)103 void lcl_CalcJulDate(sal_Int32& _nJulianDate,sal_Int32& _nJulianTime,const com::sun::star::util::DateTime _aDateTime)
104 {
105 com::sun::star::util::DateTime aDateTime = _aDateTime;
106 // weird: months fix
107 if (aDateTime.Month > 12)
108 {
109 aDateTime.Month--;
110 sal_uInt16 delta = _aDateTime.Month / 12;
111 aDateTime.Year += delta;
112 aDateTime.Month -= delta * 12;
113 aDateTime.Month++;
114 }
115
116 _nJulianTime = ((aDateTime.Hours*3600000)+(aDateTime.Minutes*60000)+(aDateTime.Seconds*1000)+(aDateTime.HundredthSeconds*10));
117 /* conversion factors */
118 sal_uInt16 iy0;
119 sal_uInt16 im0;
120 if ( aDateTime.Month <= 2 )
121 {
122 iy0 = aDateTime.Year - 1;
123 im0 = aDateTime.Month + 12;
124 }
125 else
126 {
127 iy0 = aDateTime.Year;
128 im0 = aDateTime.Month;
129 }
130 sal_Int32 ia = iy0 / 100;
131 sal_Int32 ib = 2 - ia + (ia >> 2);
132 /* calculate julian date */
133 if ( aDateTime.Year <= 0 )
134 {
135 _nJulianDate = (sal_Int32) ((365.25 * iy0) - 0.75)
136 + (sal_Int32) (30.6001 * (im0 + 1) )
137 + aDateTime.Day + 1720994;
138 } // if ( _aDateTime.Year <= 0 )
139 else
140 {
141 _nJulianDate = static_cast<sal_Int32>( ((365.25 * iy0)
142 + (sal_Int32) (30.6001 * (im0 + 1))
143 + aDateTime.Day + 1720994));
144 }
145 double JD = _nJulianDate + 0.5;
146 _nJulianDate = (sal_Int32)( JD + 0.5);
147 const double gyr = aDateTime.Year + (0.01 * aDateTime.Month) + (0.0001 * aDateTime.Day);
148 if ( gyr >= 1582.1015 ) /* on or after 15 October 1582 */
149 _nJulianDate += ib;
150 }
151
152 /**
153 calculates date time from the Julian Date
154 */
lcl_CalDate(sal_Int32 _nJulianDate,sal_Int32 _nJulianTime,com::sun::star::util::DateTime & _rDateTime)155 void lcl_CalDate(sal_Int32 _nJulianDate,sal_Int32 _nJulianTime,com::sun::star::util::DateTime& _rDateTime)
156 {
157 if ( _nJulianDate )
158 {
159 sal_Int32 ialp;
160 sal_Int32 ka = _nJulianDate;
161 if ( _nJulianDate >= 2299161 )
162 {
163 ialp = (sal_Int32)( ((double) _nJulianDate - 1867216.25 ) / ( 36524.25 ));
164 ka = _nJulianDate + 1 + ialp - ( ialp >> 2 );
165 }
166 sal_Int32 kb = ka + 1524;
167 sal_Int32 kc = (sal_Int32) ( ((double) kb - 122.1 ) / 365.25 );
168 sal_Int32 kd = (sal_Int32) ((double) kc * 365.25);
169 sal_Int32 ke = (sal_Int32) ((double) ( kb - kd ) / 30.6001 );
170 _rDateTime.Day = static_cast<sal_uInt16>(kb - kd - ((sal_Int32) ( (double) ke * 30.6001 )));
171 if ( ke > 13 )
172 _rDateTime.Month = static_cast<sal_uInt16>(ke - 13);
173 else
174 _rDateTime.Month = static_cast<sal_uInt16>(ke - 1);
175 if ( (_rDateTime.Month == 2) && (_rDateTime.Day > 28) )
176 _rDateTime.Day = 29;
177 if ( (_rDateTime.Month == 2) && (_rDateTime.Day == 29) && (ke == 3) )
178 _rDateTime.Year = static_cast<sal_uInt16>(kc - 4716);
179 else if ( _rDateTime.Month > 2 )
180 _rDateTime.Year = static_cast<sal_uInt16>(kc - 4716);
181 else
182 _rDateTime.Year = static_cast<sal_uInt16>(kc - 4715);
183 } // if ( _nJulianDate )
184
185 if ( _nJulianTime )
186 {
187 double d_s = _nJulianTime / 1000;
188 double d_m = d_s / 60;
189 double d_h = d_m / 60;
190 _rDateTime.Hours = (sal_uInt16) (d_h);
191 _rDateTime.Minutes = (sal_uInt16) d_m; // integer _aDateTime.Minutes
192 //// weird: time fix
193 // int test = (_rDateTime.Hours % 3) * 100 + _rDateTime.Minutes;
194 //int test_tbl[] = {0, 1, 2, 11, 12, 13, 22, 23, 24, 25, 34, 35, 36,
195 // 45, 46, 47, 56, 57, 58, 107, 108, 109, 110, 119, 120, 121,
196 // 130, 131, 132, 141, 142, 143, 152, 153, 154, 155, 204, 205,
197 // 206, 215, 216, 217, 226, 227, 228, 237, 238, 239, 240, 249,
198 // 250, 251};
199 // for (int i = 0; i < sizeof(test_tbl)/sizeof(test_tbl[0]); i++)
200 //{
201 // if (test == test_tbl[i])
202 // {
203 // // frac += 0.000012;
204 // //d_hour = frac * 24.0;
205 // _rDateTime.Hours = (sal_uInt16)d_hour;
206 // d_minute = (d_hour - (double)_rDateTime.Hours) * 60.0;
207 // _rDateTime.Minutes = (sal_uInt16)d_minute;
208 // break;
209 // }
210 // }
211
212 _rDateTime.Seconds = static_cast<sal_uInt16>(( d_m - (double) _rDateTime.Minutes ) * 60.0);
213 }
214 }
215
216 }
217
218 // -------------------------------------------------------------------------
readHeader()219 void ODbaseTable::readHeader()
220 {
221 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::readHeader" );
222 OSL_ENSURE(m_pFileStream,"No Stream available!");
223 if(!m_pFileStream)
224 return;
225 m_pFileStream->RefreshBuffer(); // sicherstellen, dass die Kopfinformationen tatsaechlich neu gelesen werden
226 m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
227
228 sal_uInt8 nType=0;
229 (*m_pFileStream) >> nType;
230 if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
231 throwInvalidDbaseFormat();
232
233 m_pFileStream->Read((char*)(&m_aHeader.db_aedat), 3*sizeof(sal_uInt8));
234 if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
235 throwInvalidDbaseFormat();
236 (*m_pFileStream) >> m_aHeader.db_anz;
237 if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
238 throwInvalidDbaseFormat();
239 (*m_pFileStream) >> m_aHeader.db_kopf;
240 if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
241 throwInvalidDbaseFormat();
242 (*m_pFileStream) >> m_aHeader.db_slng;
243 if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
244 throwInvalidDbaseFormat();
245 m_pFileStream->Read((char*)(&m_aHeader.db_frei), 20*sizeof(sal_uInt8));
246 if(ERRCODE_NONE != m_pFileStream->GetErrorCode())
247 throwInvalidDbaseFormat();
248
249 if ( ( ( m_aHeader.db_kopf - 1 ) / 32 - 1 ) <= 0 ) // anzahl felder
250 {
251 // no dbase file
252 throwInvalidDbaseFormat();
253 }
254 else
255 {
256 // Konsistenzpruefung des Header:
257 m_aHeader.db_typ = (DBFType)nType;
258 switch (m_aHeader.db_typ)
259 {
260 case dBaseIII:
261 case dBaseIV:
262 case dBaseV:
263 case VisualFoxPro:
264 case VisualFoxProAuto:
265 case dBaseFS:
266 case dBaseFSMemo:
267 case dBaseIVMemoSQL:
268 case dBaseIIIMemo:
269 case FoxProMemo:
270 m_pFileStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
271 if ( m_aHeader.db_frei[17] != 0x00
272 && !m_aHeader.db_frei[18] && !m_aHeader.db_frei[19] && getConnection()->isTextEncodingDefaulted() )
273 {
274 switch(m_aHeader.db_frei[17])
275 {
276 case 0x01: m_eEncoding = RTL_TEXTENCODING_IBM_437; break; // DOS USA code page 437
277 case 0x02: m_eEncoding = RTL_TEXTENCODING_IBM_850; break; // DOS Multilingual code page 850
278 case 0x03: m_eEncoding = RTL_TEXTENCODING_MS_1252; break; // Windows ANSI code page 1252
279 case 0x04: m_eEncoding = RTL_TEXTENCODING_APPLE_ROMAN; break; // Standard Macintosh
280 case 0x64: m_eEncoding = RTL_TEXTENCODING_IBM_852; break; // EE MS-DOS code page 852
281 case 0x65: m_eEncoding = RTL_TEXTENCODING_IBM_865; break; // Nordic MS-DOS code page 865
282 case 0x66: m_eEncoding = RTL_TEXTENCODING_IBM_866; break; // Russian MS-DOS code page 866
283 case 0x67: m_eEncoding = RTL_TEXTENCODING_IBM_861; break; // Icelandic MS-DOS
284 //case 0x68: m_eEncoding = ; break; // Kamenicky (Czech) MS-DOS
285 //case 0x69: m_eEncoding = ; break; // Mazovia (Polish) MS-DOS
286 case 0x6A: m_eEncoding = RTL_TEXTENCODING_IBM_737; break; // Greek MS-DOS (437G)
287 case 0x6B: m_eEncoding = RTL_TEXTENCODING_IBM_857; break; // Turkish MS-DOS
288 case 0x96: m_eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC; break; // Russian Macintosh
289 case 0x97: m_eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO; break; // Eastern European Macintosh
290 case 0x98: m_eEncoding = RTL_TEXTENCODING_APPLE_GREEK; break; // Greek Macintosh
291 case 0xC8: m_eEncoding = RTL_TEXTENCODING_MS_1250; break; // Windows EE code page 1250
292 case 0xC9: m_eEncoding = RTL_TEXTENCODING_MS_1251; break; // Russian Windows
293 case 0xCA: m_eEncoding = RTL_TEXTENCODING_MS_1254; break; // Turkish Windows
294 case 0xCB: m_eEncoding = RTL_TEXTENCODING_MS_1253; break; // Greek Windows
295 default:
296 break;
297 }
298 }
299 break;
300 case dBaseIVMemo:
301 m_pFileStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
302 break;
303 default:
304 {
305 throwInvalidDbaseFormat();
306 }
307 }
308 }
309 }
310 // -------------------------------------------------------------------------
fillColumns()311 void ODbaseTable::fillColumns()
312 {
313 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::fillColumns" );
314 m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
315 m_pFileStream->Seek(32L);
316
317 if(!m_aColumns.isValid())
318 m_aColumns = new OSQLColumns();
319 else
320 m_aColumns->get().clear();
321
322 m_aTypes.clear();
323 m_aPrecisions.clear();
324 m_aScales.clear();
325
326 // Anzahl Felder:
327 const sal_Int32 nFieldCount = (m_aHeader.db_kopf - 1) / 32 - 1;
328 OSL_ENSURE(nFieldCount,"No columns in table!");
329
330 m_aColumns->get().reserve(nFieldCount);
331 m_aTypes.reserve(nFieldCount);
332 m_aPrecisions.reserve(nFieldCount);
333 m_aScales.reserve(nFieldCount);
334
335 String aStrFieldName;
336 aStrFieldName.AssignAscii("Column");
337 ::rtl::OUString aTypeName;
338 static const ::rtl::OUString sVARCHAR(RTL_CONSTASCII_USTRINGPARAM("VARCHAR"));
339 const sal_Bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
340 const bool bFoxPro = m_aHeader.db_typ == VisualFoxPro || m_aHeader.db_typ == VisualFoxProAuto || m_aHeader.db_typ == FoxProMemo;
341
342 sal_Int32 i = 0;
343 for (; i < nFieldCount; i++)
344 {
345 DBFColumn aDBFColumn;
346 m_pFileStream->Read((char*)&aDBFColumn, sizeof(aDBFColumn));
347 if ( FIELD_DESCRIPTOR_TERMINATOR == aDBFColumn.db_fnm[0] ) // 0x0D stored as the Field Descriptor terminator.
348 break;
349
350 sal_Bool bIsRowVersion = bFoxPro && ( aDBFColumn.db_frei2[0] & 0x01 ) == 0x01;
351 //if ( bFoxPro && ( aDBFColumn.db_frei2[0] & 0x01 ) == 0x01 ) // system column not visible to user
352 // continue;
353 const String aColumnName((const char *)aDBFColumn.db_fnm,m_eEncoding);
354
355 m_aRealFieldLengths.push_back(aDBFColumn.db_flng);
356 sal_Int32 nPrecision = aDBFColumn.db_flng;
357 sal_Int32 eType;
358 sal_Bool bIsCurrency = sal_False;
359
360 char cType[2];
361 cType[0] = aDBFColumn.db_typ;
362 cType[1] = 0;
363 aTypeName = ::rtl::OUString::createFromAscii(cType);
364 OSL_TRACE("column type: %c",aDBFColumn.db_typ);
365
366 switch (aDBFColumn.db_typ)
367 {
368 case 'C':
369 eType = DataType::VARCHAR;
370 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("VARCHAR"));
371 break;
372 case 'F':
373 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DECIMAL"));
374 case 'N':
375 if ( aDBFColumn.db_typ == 'N' )
376 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NUMERIC"));
377 eType = DataType::DECIMAL;
378
379 // Bei numerischen Feldern werden zwei Zeichen mehr geschrieben, als die Precision der Spaltenbeschreibung eigentlich
380 // angibt, um Platz fuer das eventuelle Vorzeichen und das Komma zu haben. Das muss ich jetzt aber wieder rausrechnen.
381 nPrecision = SvDbaseConverter::ConvertPrecisionToOdbc(nPrecision,aDBFColumn.db_dez);
382 // leider gilt das eben Gesagte nicht fuer aeltere Versionen ....
383 break;
384 case 'L':
385 eType = DataType::BIT;
386 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BOOLEAN"));
387 break;
388 case 'Y':
389 bIsCurrency = sal_True;
390 eType = DataType::DOUBLE;
391 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DOUBLE"));
392 break;
393 case 'D':
394 eType = DataType::DATE;
395 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DATE"));
396 break;
397 case 'T':
398 eType = DataType::TIMESTAMP;
399 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TIMESTAMP"));
400 break;
401 case 'I':
402 eType = DataType::INTEGER;
403 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("INTEGER"));
404 break;
405 case 'M':
406 if ( bFoxPro && ( aDBFColumn.db_frei2[0] & 0x04 ) == 0x04 )
407 {
408 eType = DataType::LONGVARBINARY;
409 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LONGVARBINARY"));
410 }
411 else
412 {
413 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LONGVARCHAR"));
414 eType = DataType::LONGVARCHAR;
415 }
416 nPrecision = 2147483647;
417 break;
418 case 'P':
419 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LONGVARBINARY"));
420 eType = DataType::LONGVARBINARY;
421 nPrecision = 2147483647;
422 break;
423 case '0':
424 case 'B':
425 if ( m_aHeader.db_typ == VisualFoxPro || m_aHeader.db_typ == VisualFoxProAuto )
426 {
427 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DOUBLE"));
428 eType = DataType::DOUBLE;
429 }
430 else
431 {
432 aTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("LONGVARBINARY"));
433 eType = DataType::LONGVARBINARY;
434 nPrecision = 2147483647;
435 }
436 break;
437 default:
438 eType = DataType::OTHER;
439 }
440
441 m_aTypes.push_back(eType);
442 m_aPrecisions.push_back(nPrecision);
443 m_aScales.push_back(aDBFColumn.db_dez);
444
445 Reference< XPropertySet> xCol = new sdbcx::OColumn(aColumnName,
446 aTypeName,
447 ::rtl::OUString(),
448 ::rtl::OUString(),
449 ColumnValue::NULLABLE,
450 nPrecision,
451 aDBFColumn.db_dez,
452 eType,
453 sal_False,
454 bIsRowVersion,
455 bIsCurrency,
456 bCase);
457 m_aColumns->get().push_back(xCol);
458 } // for (; i < nFieldCount; i++)
459 OSL_ENSURE(i,"No columns in table!");
460 }
461 // -------------------------------------------------------------------------
ODbaseTable(sdbcx::OCollection * _pTables,ODbaseConnection * _pConnection)462 ODbaseTable::ODbaseTable(sdbcx::OCollection* _pTables,ODbaseConnection* _pConnection)
463 :ODbaseTable_BASE(_pTables,_pConnection)
464 ,m_pMemoStream(NULL)
465 ,m_bWriteableMemo(sal_False)
466 {
467 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::ODbaseTable" );
468 // initialize the header
469 m_aHeader.db_typ = dBaseIII;
470 m_aHeader.db_anz = 0;
471 m_aHeader.db_kopf = 0;
472 m_aHeader.db_slng = 0;
473 m_eEncoding = getConnection()->getTextEncoding();
474 }
475 // -------------------------------------------------------------------------
ODbaseTable(sdbcx::OCollection * _pTables,ODbaseConnection * _pConnection,const::rtl::OUString & _Name,const::rtl::OUString & _Type,const::rtl::OUString & _Description,const::rtl::OUString & _SchemaName,const::rtl::OUString & _CatalogName)476 ODbaseTable::ODbaseTable(sdbcx::OCollection* _pTables,ODbaseConnection* _pConnection,
477 const ::rtl::OUString& _Name,
478 const ::rtl::OUString& _Type,
479 const ::rtl::OUString& _Description ,
480 const ::rtl::OUString& _SchemaName,
481 const ::rtl::OUString& _CatalogName
482 ) : ODbaseTable_BASE(_pTables,_pConnection,_Name,
483 _Type,
484 _Description,
485 _SchemaName,
486 _CatalogName)
487 ,m_pMemoStream(NULL)
488 ,m_bWriteableMemo(sal_False)
489 {
490 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::ODbaseTable" );
491 m_eEncoding = getConnection()->getTextEncoding();
492 }
493
494 // -----------------------------------------------------------------------------
construct()495 void ODbaseTable::construct()
496 {
497 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::construct" );
498 // initialize the header
499 m_aHeader.db_typ = dBaseIII;
500 m_aHeader.db_anz = 0;
501 m_aHeader.db_kopf = 0;
502 m_aHeader.db_slng = 0;
503 m_aMemoHeader.db_size = 0;
504
505 String sFileName(getEntry(m_pConnection,m_Name));
506
507 INetURLObject aURL;
508 aURL.SetURL(sFileName);
509
510 OSL_ENSURE( m_pConnection->matchesExtension( aURL.getExtension() ),
511 "ODbaseTable::ODbaseTable: invalid extension!");
512 // getEntry is expected to ensure the corect file name
513
514 m_pFileStream = createStream_simpleError( sFileName, STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYWRITE);
515 m_bWriteable = ( m_pFileStream != NULL );
516
517 if ( !m_pFileStream )
518 {
519 m_bWriteable = sal_False;
520 m_pFileStream = createStream_simpleError( sFileName, STREAM_READ | STREAM_NOCREATE | STREAM_SHARE_DENYNONE);
521 }
522
523 if(m_pFileStream)
524 {
525 readHeader();
526 if (HasMemoFields())
527 {
528 // Memo-Dateinamen bilden (.DBT):
529 // nyi: Unschoen fuer Unix und Mac!
530
531 if ( m_aHeader.db_typ == FoxProMemo || VisualFoxPro == m_aHeader.db_typ || VisualFoxProAuto == m_aHeader.db_typ ) // foxpro uses another extension
532 aURL.SetExtension(String::CreateFromAscii("fpt"));
533 else
534 aURL.SetExtension(String::CreateFromAscii("dbt"));
535
536 // Wenn die Memodatei nicht gefunden wird, werden die Daten trotzdem angezeigt
537 // allerdings koennen keine Updates durchgefuehrt werden
538 // jedoch die Operation wird ausgefuehrt
539 m_pMemoStream = createStream_simpleError( aURL.GetMainURL(INetURLObject::NO_DECODE), STREAM_READWRITE | STREAM_NOCREATE | STREAM_SHARE_DENYWRITE);
540 if ( !m_pMemoStream )
541 {
542 m_bWriteableMemo = sal_False;
543 m_pMemoStream = createStream_simpleError( aURL.GetMainURL(INetURLObject::NO_DECODE), STREAM_READ | STREAM_NOCREATE | STREAM_SHARE_DENYNONE);
544 }
545 if (m_pMemoStream)
546 ReadMemoHeader();
547 }
548 // if(!m_pColumns && (!m_aColumns.isValid() || !m_aColumns->size()))
549 fillColumns();
550
551 sal_uInt32 nFileSize = lcl_getFileSize(*m_pFileStream);
552 m_pFileStream->Seek(STREAM_SEEK_TO_BEGIN);
553 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
554 m_aHeader.db_anz = ((nFileSize-m_aHeader.db_kopf)/m_aHeader.db_slng);
555
556 // Buffersize abhaengig von der Filegroesse
557 m_pFileStream->SetBufferSize(nFileSize > 1000000 ? 32768 :
558 nFileSize > 100000 ? 16384 :
559 nFileSize > 10000 ? 4096 : 1024);
560
561 if (m_pMemoStream)
562 {
563 // Puffer genau auf Laenge eines Satzes stellen
564 m_pMemoStream->Seek(STREAM_SEEK_TO_END);
565 nFileSize = m_pMemoStream->Tell();
566 m_pMemoStream->Seek(STREAM_SEEK_TO_BEGIN);
567
568 // Buffersize abhaengig von der Filegroesse
569 m_pMemoStream->SetBufferSize(nFileSize > 1000000 ? 32768 :
570 nFileSize > 100000 ? 16384 :
571 nFileSize > 10000 ? 4096 :
572 m_aMemoHeader.db_size);
573 }
574
575 AllocBuffer();
576 }
577 }
578 //------------------------------------------------------------------
ReadMemoHeader()579 sal_Bool ODbaseTable::ReadMemoHeader()
580 {
581 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::ReadMemoHeader" );
582 m_pMemoStream->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
583 m_pMemoStream->RefreshBuffer(); // sicherstellen das die Kopfinformationen tatsaechlich neu gelesen werden
584 m_pMemoStream->Seek(0L);
585
586 (*m_pMemoStream) >> m_aMemoHeader.db_next;
587 switch (m_aHeader.db_typ)
588 {
589 case dBaseIIIMemo: // dBase III: feste Blockgroesse
590 case dBaseIVMemo:
591 // manchmal wird aber auch dBase3 dBase4 Memo zugeordnet
592 m_pMemoStream->Seek(20L);
593 (*m_pMemoStream) >> m_aMemoHeader.db_size;
594 if (m_aMemoHeader.db_size > 1 && m_aMemoHeader.db_size != 512) // 1 steht auch fuer dBase 3
595 m_aMemoHeader.db_typ = MemodBaseIV;
596 else if (m_aMemoHeader.db_size > 1 && m_aMemoHeader.db_size == 512)
597 {
598 // nun gibt es noch manche Dateien, die verwenden eine Groessenangabe,
599 // sind aber dennoch dBase Dateien
600 char sHeader[4];
601 m_pMemoStream->Seek(m_aMemoHeader.db_size);
602 m_pMemoStream->Read(sHeader,4);
603
604 if ((m_pMemoStream->GetErrorCode() != ERRCODE_NONE) || ((sal_uInt8)sHeader[0]) != 0xFF || ((sal_uInt8)sHeader[1]) != 0xFF || ((sal_uInt8)sHeader[2]) != 0x08)
605 m_aMemoHeader.db_typ = MemodBaseIII;
606 else
607 m_aMemoHeader.db_typ = MemodBaseIV;
608 }
609 else
610 {
611 m_aMemoHeader.db_typ = MemodBaseIII;
612 m_aMemoHeader.db_size = 512;
613 }
614 break;
615 case VisualFoxPro:
616 case VisualFoxProAuto:
617 case FoxProMemo:
618 m_aMemoHeader.db_typ = MemoFoxPro;
619 m_pMemoStream->Seek(6L);
620 m_pMemoStream->SetNumberFormatInt(NUMBERFORMAT_INT_BIGENDIAN);
621 (*m_pMemoStream) >> m_aMemoHeader.db_size;
622 break;
623 default:
624 OSL_ENSURE( false, "ODbaseTable::ReadMemoHeader: unsupported memo type!" );
625 break;
626 }
627 return sal_True;
628 }
629 // -------------------------------------------------------------------------
getEntry(OConnection * _pConnection,const::rtl::OUString & _sName)630 String ODbaseTable::getEntry(OConnection* _pConnection,const ::rtl::OUString& _sName )
631 {
632 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getEntry" );
633 ::rtl::OUString sURL;
634 try
635 {
636 Reference< XResultSet > xDir = _pConnection->getDir()->getStaticResultSet();
637 Reference< XRow> xRow(xDir,UNO_QUERY);
638 ::rtl::OUString sName;
639 ::rtl::OUString sExt;
640 INetURLObject aURL;
641 static const ::rtl::OUString s_sSeparator(RTL_CONSTASCII_USTRINGPARAM("/"));
642 xDir->beforeFirst();
643 while(xDir->next())
644 {
645 sName = xRow->getString(1);
646 aURL.SetSmartProtocol(INET_PROT_FILE);
647 String sUrl = _pConnection->getURL() + s_sSeparator + sName;
648 aURL.SetSmartURL( sUrl );
649
650 // cut the extension
651 sExt = aURL.getExtension();
652
653 // name and extension have to coincide
654 if ( _pConnection->matchesExtension( sExt ) )
655 {
656 sName = sName.replaceAt(sName.getLength()-(sExt.getLength()+1),sExt.getLength()+1,::rtl::OUString());
657 if ( sName == _sName )
658 {
659 Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY );
660 sURL = xContentAccess->queryContentIdentifierString();
661 break;
662 }
663 }
664 }
665 xDir->beforeFirst(); // move back to before first record
666 }
667 catch(Exception&)
668 {
669 OSL_ASSERT(0);
670 }
671 return sURL;
672 }
673 // -------------------------------------------------------------------------
refreshColumns()674 void ODbaseTable::refreshColumns()
675 {
676 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::refreshColumns" );
677 ::osl::MutexGuard aGuard( m_aMutex );
678
679 TStringVector aVector;
680 aVector.reserve(m_aColumns->get().size());
681
682 for(OSQLColumns::Vector::const_iterator aIter = m_aColumns->get().begin();aIter != m_aColumns->get().end();++aIter)
683 aVector.push_back(Reference< XNamed>(*aIter,UNO_QUERY)->getName());
684
685 if(m_pColumns)
686 m_pColumns->reFill(aVector);
687 else
688 m_pColumns = new ODbaseColumns(this,m_aMutex,aVector);
689 }
690 // -------------------------------------------------------------------------
refreshIndexes()691 void ODbaseTable::refreshIndexes()
692 {
693 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::refreshIndexes" );
694 TStringVector aVector;
695 if(m_pFileStream && (!m_pIndexes || m_pIndexes->getCount() == 0))
696 {
697 INetURLObject aURL;
698 aURL.SetURL(getEntry(m_pConnection,m_Name));
699
700 aURL.setExtension(String::CreateFromAscii("inf"));
701 Config aInfFile(aURL.getFSysPath(INetURLObject::FSYS_DETECT));
702 aInfFile.SetGroup(dBASE_III_GROUP);
703 sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
704 ByteString aKeyName;
705 ByteString aIndexName;
706
707 for (sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++)
708 {
709 // Verweist der Key auf ein Indexfile?...
710 aKeyName = aInfFile.GetKeyName( nKey );
711 //...wenn ja, Indexliste der Tabelle hinzufuegen
712 if (aKeyName.Copy(0,3) == ByteString("NDX") )
713 {
714 aIndexName = aInfFile.ReadKey(aKeyName);
715 aURL.setName(String(aIndexName,m_eEncoding));
716 try
717 {
718 Content aCnt(aURL.GetMainURL(INetURLObject::NO_DECODE),Reference<XCommandEnvironment>());
719 if (aCnt.isDocument())
720 {
721 aVector.push_back(aURL.getBase());
722 }
723 }
724 catch(Exception&) // a execption is thrown when no file exists
725 {
726 }
727 }
728 }
729 }
730 if(m_pIndexes)
731 m_pIndexes->reFill(aVector);
732 else
733 m_pIndexes = new ODbaseIndexes(this,m_aMutex,aVector);
734 }
735
736 // -------------------------------------------------------------------------
disposing(void)737 void SAL_CALL ODbaseTable::disposing(void)
738 {
739 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::disposing" );
740 OFileTable::disposing();
741 ::osl::MutexGuard aGuard(m_aMutex);
742 m_aColumns = NULL;
743 }
744 // -------------------------------------------------------------------------
getTypes()745 Sequence< Type > SAL_CALL ODbaseTable::getTypes( ) throw(RuntimeException)
746 {
747 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getTypes" );
748 Sequence< Type > aTypes = OTable_TYPEDEF::getTypes();
749 ::std::vector<Type> aOwnTypes;
750 aOwnTypes.reserve(aTypes.getLength());
751
752 const Type* pBegin = aTypes.getConstArray();
753 const Type* pEnd = pBegin + aTypes.getLength();
754 for(;pBegin != pEnd;++pBegin)
755 {
756 if(!(*pBegin == ::getCppuType((const Reference<XKeysSupplier>*)0) ||
757 // *pBegin == ::getCppuType((const Reference<XAlterTable>*)0) ||
758 *pBegin == ::getCppuType((const Reference<XDataDescriptorFactory>*)0)))
759 {
760 aOwnTypes.push_back(*pBegin);
761 }
762 }
763 aOwnTypes.push_back(::getCppuType( (const Reference< ::com::sun::star::lang::XUnoTunnel > *)0 ));
764 Type *pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0];
765 return Sequence< Type >(pTypes, aOwnTypes.size());
766 }
767
768 // -------------------------------------------------------------------------
queryInterface(const Type & rType)769 Any SAL_CALL ODbaseTable::queryInterface( const Type & rType ) throw(RuntimeException)
770 {
771 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::queryInterface" );
772 if( rType == ::getCppuType((const Reference<XKeysSupplier>*)0) ||
773 rType == ::getCppuType((const Reference<XDataDescriptorFactory>*)0))
774 return Any();
775
776 Any aRet = OTable_TYPEDEF::queryInterface(rType);
777 return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< ::com::sun::star::lang::XUnoTunnel*> (this));
778 }
779
780 //--------------------------------------------------------------------------
getUnoTunnelImplementationId()781 Sequence< sal_Int8 > ODbaseTable::getUnoTunnelImplementationId()
782 {
783 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getUnoTunnelImplementationId" );
784 static ::cppu::OImplementationId * pId = 0;
785 if (! pId)
786 {
787 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
788 if (! pId)
789 {
790 static ::cppu::OImplementationId aId;
791 pId = &aId;
792 }
793 }
794 return pId->getImplementationId();
795 }
796
797 // com::sun::star::lang::XUnoTunnel
798 //------------------------------------------------------------------
getSomething(const Sequence<sal_Int8> & rId)799 sal_Int64 ODbaseTable::getSomething( const Sequence< sal_Int8 > & rId ) throw (RuntimeException)
800 {
801 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getSomething" );
802 return (rId.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), rId.getConstArray(), 16 ) )
803 ? reinterpret_cast< sal_Int64 >( this )
804 : ODbaseTable_BASE::getSomething(rId);
805 }
806 //------------------------------------------------------------------
fetchRow(OValueRefRow & _rRow,const OSQLColumns & _rCols,sal_Bool _bUseTableDefs,sal_Bool bRetrieveData)807 sal_Bool ODbaseTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols, sal_Bool _bUseTableDefs,sal_Bool bRetrieveData)
808 {
809 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::fetchRow" );
810 // Einlesen der Daten
811 sal_Bool bIsCurRecordDeleted = ((char)m_pBuffer[0] == '*') ? sal_True : sal_False;
812
813 // only read the bookmark
814
815 // Satz als geloescht markieren
816 // rRow.setState(bIsCurRecordDeleted ? ROW_DELETED : ROW_CLEAN );
817 _rRow->setDeleted(bIsCurRecordDeleted);
818 *(_rRow->get())[0] = m_nFilePos;
819
820 if (!bRetrieveData)
821 return sal_True;
822
823 sal_Size nByteOffset = 1;
824 // Felder:
825 OSQLColumns::Vector::const_iterator aIter = _rCols.get().begin();
826 OSQLColumns::Vector::const_iterator aEnd = _rCols.get().end();
827 const sal_Size nCount = _rRow->get().size();
828 for (sal_Size i = 1; aIter != aEnd && nByteOffset <= m_nBufferSize && i < nCount;++aIter, i++)
829 {
830 // Laengen je nach Datentyp:
831 sal_Int32 nLen = 0;
832 sal_Int32 nType = 0;
833 if(_bUseTableDefs)
834 {
835 nLen = m_aPrecisions[i-1];
836 nType = m_aTypes[i-1];
837 }
838 else
839 {
840 (*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nLen;
841 (*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
842 }
843 switch(nType)
844 {
845 case DataType::INTEGER:
846 case DataType::DOUBLE:
847 case DataType::TIMESTAMP:
848 case DataType::DATE:
849 case DataType::BIT:
850 case DataType::LONGVARCHAR:
851 case DataType::LONGVARBINARY:
852 nLen = m_aRealFieldLengths[i-1];
853 break;
854 case DataType::DECIMAL:
855 if(_bUseTableDefs)
856 nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,m_aScales[i-1]);
857 else
858 nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,getINT32((*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE))));
859 break; // das Vorzeichen und das Komma
860
861 case DataType::BINARY:
862 case DataType::OTHER:
863 nByteOffset += nLen;
864 continue;
865 }
866
867 // Ist die Variable ueberhaupt gebunden?
868 if ( !(_rRow->get())[i]->isBound() )
869 {
870 // Nein - naechstes Feld.
871 nByteOffset += nLen;
872 OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
873 continue;
874 } // if ( !(_rRow->get())[i]->isBound() )
875 if ( ( nByteOffset + nLen) > m_nBufferSize )
876 break; // length doesn't match buffer size.
877
878 char *pData = (char *) (m_pBuffer + nByteOffset);
879
880 // (*_rRow)[i].setType(nType);
881
882 if (nType == DataType::CHAR || nType == DataType::VARCHAR)
883 {
884 char cLast = pData[nLen];
885 pData[nLen] = 0;
886 String aStr(pData,(xub_StrLen)nLen,m_eEncoding);
887 aStr.EraseTrailingChars();
888
889 if ( aStr.Len() )
890 *(_rRow->get())[i] = ::rtl::OUString(aStr);
891 else// keine StringLaenge, dann NULL
892 (_rRow->get())[i]->setNull();
893
894 pData[nLen] = cLast;
895 } // if (nType == DataType::CHAR || nType == DataType::VARCHAR)
896 else if ( DataType::TIMESTAMP == nType )
897 {
898 sal_Int32 nDate = 0,nTime = 0;
899 memcpy(&nDate, pData, 4);
900 memcpy(&nTime, pData+ 4, 4);
901 if ( !nDate && !nTime )
902 {
903 (_rRow->get())[i]->setNull();
904 }
905 else
906 {
907 ::com::sun::star::util::DateTime aDateTime;
908 lcl_CalDate(nDate,nTime,aDateTime);
909 *(_rRow->get())[i] = aDateTime;
910 }
911 }
912 else if ( DataType::INTEGER == nType )
913 {
914 sal_Int32 nValue = 0;
915 memcpy(&nValue, pData, nLen);
916 *(_rRow->get())[i] = nValue;
917 }
918 else if ( DataType::DOUBLE == nType )
919 {
920 double d = 0.0;
921 if (getBOOL((*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency wird gesondert behandelt
922 {
923 sal_Int64 nValue = 0;
924 memcpy(&nValue, pData, nLen);
925
926 if ( m_aScales[i-1] )
927 d = (double)(nValue / pow(10.0,(int)m_aScales[i-1]));
928 else
929 d = (double)(nValue);
930 }
931 else
932 {
933 memcpy(&d, pData, nLen);
934 }
935
936 *(_rRow->get())[i] = d;
937 }
938 else
939 {
940 // Falls Nul-Zeichen im String enthalten sind, in Blanks umwandeln!
941 for (sal_Int32 k = 0; k < nLen; k++)
942 {
943 if (pData[k] == '\0')
944 pData[k] = ' ';
945 }
946
947 String aStr(pData, (xub_StrLen)nLen,m_eEncoding); // Spaces am Anfang und am Ende entfernen:
948 aStr.EraseLeadingChars();
949 aStr.EraseTrailingChars();
950
951 if (!aStr.Len())
952 {
953 nByteOffset += nLen;
954 (_rRow->get())[i]->setNull(); // keine Werte -> fertig
955 continue;
956 }
957
958 switch (nType)
959 {
960 case DataType::DATE:
961 {
962 if (aStr.Len() != nLen)
963 {
964 (_rRow->get())[i]->setNull();
965 break;
966 }
967 const sal_uInt16 nYear = (sal_uInt16)aStr.Copy( 0, 4 ).ToInt32();
968 const sal_uInt16 nMonth = (sal_uInt16)aStr.Copy( 4, 2 ).ToInt32();
969 const sal_uInt16 nDay = (sal_uInt16)aStr.Copy( 6, 2 ).ToInt32();
970
971 const ::com::sun::star::util::Date aDate(nDay,nMonth,nYear);
972 *(_rRow->get())[i] = aDate;
973 }
974 break;
975 case DataType::DECIMAL:
976 *(_rRow->get())[i] = ORowSetValue(aStr);
977 // pVal->setDouble(SdbTools::ToDouble(aStr));
978 break;
979 case DataType::BIT:
980 {
981 sal_Bool b;
982 switch (* ((const char *)pData))
983 {
984 case 'T':
985 case 'Y':
986 case 'J': b = sal_True; break;
987 default: b = sal_False; break;
988 }
989 *(_rRow->get())[i] = b;
990 // pVal->setDouble(b);
991 }
992 break;
993 case DataType::LONGVARBINARY:
994 case DataType::BINARY:
995 case DataType::LONGVARCHAR:
996 {
997 const long nBlockNo = aStr.ToInt32(); // Blocknummer lesen
998 if (nBlockNo > 0 && m_pMemoStream) // Daten aus Memo-Datei lesen, nur wenn
999 {
1000 if ( !ReadMemo(nBlockNo, (_rRow->get())[i]->get()) )
1001 break;
1002 }
1003 else
1004 (_rRow->get())[i]->setNull();
1005 } break;
1006 default:
1007 OSL_ASSERT("Falscher Type");
1008 }
1009 (_rRow->get())[i]->setTypeKind(nType);
1010 }
1011
1012 nByteOffset += nLen;
1013 OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
1014 }
1015 return sal_True;
1016 }
1017 //------------------------------------------------------------------
1018 // -------------------------------------------------------------------------
FileClose()1019 void ODbaseTable::FileClose()
1020 {
1021 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::FileClose" );
1022 ::osl::MutexGuard aGuard(m_aMutex);
1023 // falls noch nicht alles geschrieben wurde
1024 if (m_pMemoStream && m_pMemoStream->IsWritable())
1025 m_pMemoStream->Flush();
1026
1027 delete m_pMemoStream;
1028 m_pMemoStream = NULL;
1029
1030 ODbaseTable_BASE::FileClose();
1031 }
1032 // -------------------------------------------------------------------------
CreateImpl()1033 sal_Bool ODbaseTable::CreateImpl()
1034 {
1035 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::CreateImpl" );
1036 OSL_ENSURE(!m_pFileStream, "SequenceError");
1037
1038 if ( m_pConnection->isCheckEnabled() && ::dbtools::convertName2SQLName(m_Name,::rtl::OUString()) != m_Name )
1039 {
1040 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
1041 STR_SQL_NAME_ERROR,
1042 "$name$", m_Name
1043 ) );
1044 ::dbtools::throwGenericSQLException( sError, *this );
1045 }
1046
1047 INetURLObject aURL;
1048 aURL.SetSmartProtocol(INET_PROT_FILE);
1049 String aName = getEntry(m_pConnection,m_Name);
1050 if(!aName.Len())
1051 {
1052 ::rtl::OUString aIdent = m_pConnection->getContent()->getIdentifier()->getContentIdentifier();
1053 if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) )
1054 aIdent += ::rtl::OUString::createFromAscii("/");
1055 aIdent += m_Name;
1056 aName = aIdent.getStr();
1057 }
1058 aURL.SetURL(aName);
1059
1060 if ( !m_pConnection->matchesExtension( aURL.getExtension() ) )
1061 aURL.setExtension(m_pConnection->getExtension());
1062
1063 try
1064 {
1065 Content aContent(aURL.GetMainURL(INetURLObject::NO_DECODE),Reference<XCommandEnvironment>());
1066 if (aContent.isDocument())
1067 {
1068 // Hack fuer Bug #30609 , nur wenn das File existiert und die Laenge > 0 gibt es einen Fehler
1069 SvStream* pFileStream = createStream_simpleError( aURL.GetMainURL(INetURLObject::NO_DECODE),STREAM_READ);
1070
1071 if (pFileStream && pFileStream->Seek(STREAM_SEEK_TO_END))
1072 {
1073 // aStatus.SetError(ERRCODE_IO_ALREADYEXISTS,TABLE,aFile.GetFull());
1074 return sal_False;
1075 }
1076 delete pFileStream;
1077 }
1078 }
1079 catch(Exception&) // a execption is thrown when no file exists
1080 {
1081 }
1082
1083 sal_Bool bMemoFile = sal_False;
1084
1085 sal_Bool bOk = CreateFile(aURL, bMemoFile);
1086
1087 FileClose();
1088
1089 if (!bOk)
1090 {
1091 try
1092 {
1093 Content aContent(aURL.GetMainURL(INetURLObject::NO_DECODE),Reference<XCommandEnvironment>());
1094 aContent.executeCommand( rtl::OUString::createFromAscii( "delete" ),bool2any( sal_True ) );
1095 }
1096 catch(Exception&) // a execption is thrown when no file exists
1097 {
1098 }
1099 return sal_False;
1100 }
1101
1102 if (bMemoFile)
1103 {
1104 String aExt = aURL.getExtension();
1105 aURL.setExtension(String::CreateFromAscii("dbt")); // extension for memo file
1106 Content aMemo1Content(aURL.GetMainURL(INetURLObject::NO_DECODE),Reference<XCommandEnvironment>());
1107
1108 sal_Bool bMemoAlreadyExists = sal_False;
1109 try
1110 {
1111 bMemoAlreadyExists = aMemo1Content.isDocument();
1112 }
1113 catch(Exception&) // a execption is thrown when no file exists
1114 {
1115 }
1116 if (bMemoAlreadyExists)
1117 {
1118 // aStatus.SetError(ERRCODE_IO_ALREADYEXISTS,MEMO,aFile.GetFull());
1119 aURL.setExtension(aExt); // kill dbf file
1120 try
1121 {
1122 Content aMemoContent(aURL.GetMainURL(INetURLObject::NO_DECODE),Reference<XCommandEnvironment>());
1123 aMemoContent.executeCommand( rtl::OUString::createFromAscii( "delete" ),bool2any( sal_True ) );
1124 }
1125 catch(const Exception&)
1126 {
1127
1128 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
1129 STR_COULD_NOT_DELETE_FILE,
1130 "$name$", aName
1131 ) );
1132 ::dbtools::throwGenericSQLException( sError, *this );
1133 }
1134 }
1135 if (!CreateMemoFile(aURL))
1136 {
1137 aURL.setExtension(aExt); // kill dbf file
1138 Content aMemoContent(aURL.GetMainURL(INetURLObject::NO_DECODE),Reference<XCommandEnvironment>());
1139 aMemoContent.executeCommand( rtl::OUString::createFromAscii( "delete" ),bool2any( sal_True ) );
1140 return sal_False;
1141 }
1142 m_aHeader.db_typ = dBaseIIIMemo;
1143 }
1144 else
1145 m_aHeader.db_typ = dBaseIII;
1146
1147 return sal_True;
1148 }
1149 // -----------------------------------------------------------------------------
throwInvalidColumnType(const sal_uInt16 _nErrorId,const::rtl::OUString & _sColumnName)1150 void ODbaseTable::throwInvalidColumnType(const sal_uInt16 _nErrorId,const ::rtl::OUString& _sColumnName)
1151 {
1152 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::throwInvalidColumnType" );
1153 try
1154 {
1155 // we have to drop the file because it is corrupted now
1156 DropImpl();
1157 }
1158 catch(const Exception&)
1159 {
1160 }
1161
1162 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
1163 _nErrorId,
1164 "$columnname$", _sColumnName
1165 ) );
1166 ::dbtools::throwGenericSQLException( sError, *this );
1167 }
1168 //------------------------------------------------------------------
1169 // erzeugt grundsaetzlich dBase IV Datei Format
CreateFile(const INetURLObject & aFile,sal_Bool & bCreateMemo)1170 sal_Bool ODbaseTable::CreateFile(const INetURLObject& aFile, sal_Bool& bCreateMemo)
1171 {
1172 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::CreateFile" );
1173 bCreateMemo = sal_False;
1174 Date aDate; // aktuelles Datum
1175
1176 m_pFileStream = createStream_simpleError( aFile.GetMainURL(INetURLObject::NO_DECODE),STREAM_READWRITE | STREAM_SHARE_DENYWRITE | STREAM_TRUNC );
1177
1178 if (!m_pFileStream)
1179 return sal_False;
1180
1181 sal_uInt8 nDbaseType = dBaseIII;
1182 Reference<XIndexAccess> xColumns(getColumns(),UNO_QUERY);
1183 Reference<XPropertySet> xCol;
1184 const ::rtl::OUString sPropType = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE);
1185
1186 try
1187 {
1188 const sal_Int32 nCount = xColumns->getCount();
1189 for(sal_Int32 i=0;i<nCount;++i)
1190 {
1191 xColumns->getByIndex(i) >>= xCol;
1192 OSL_ENSURE(xCol.is(),"This should be a column!");
1193
1194 switch (getINT32(xCol->getPropertyValue(sPropType)))
1195 {
1196 case DataType::DOUBLE:
1197 case DataType::INTEGER:
1198 case DataType::TIMESTAMP:
1199 case DataType::LONGVARBINARY:
1200 nDbaseType = VisualFoxPro;
1201 i = nCount; // no more columns need to be checked
1202 break;
1203 } // switch (getINT32(xCol->getPropertyValue(sPropType)))
1204 }
1205 }
1206 catch ( const Exception& e )
1207 {
1208 (void)e;
1209
1210 try
1211 {
1212 // we have to drop the file because it is corrupted now
1213 DropImpl();
1214 }
1215 catch(const Exception&) { }
1216 throw;
1217 }
1218
1219 char aBuffer[21]; // write buffer
1220 memset(aBuffer,0,sizeof(aBuffer));
1221
1222 m_pFileStream->Seek(0L);
1223 (*m_pFileStream) << (sal_uInt8) nDbaseType; // dBase format
1224 (*m_pFileStream) << (sal_uInt8) (aDate.GetYear() % 100); // aktuelles Datum
1225
1226
1227 (*m_pFileStream) << (sal_uInt8) aDate.GetMonth();
1228 (*m_pFileStream) << (sal_uInt8) aDate.GetDay();
1229 (*m_pFileStream) << 0L; // Anzahl der Datensaetze
1230 (*m_pFileStream) << (sal_uInt16)((m_pColumns->getCount()+1) * 32 + 1); // Kopfinformationen,
1231 // pColumns erhaelt immer eine Spalte mehr
1232 (*m_pFileStream) << (sal_uInt16) 0; // Satzlaenge wird spaeter bestimmt
1233 m_pFileStream->Write(aBuffer, 20);
1234
1235 sal_uInt16 nRecLength = 1; // Laenge 1 fuer deleted flag
1236 sal_Int32 nMaxFieldLength = m_pConnection->getMetaData()->getMaxColumnNameLength();
1237 ::rtl::OUString aName;
1238 const ::rtl::OUString sPropName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
1239 const ::rtl::OUString sPropPrec = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION);
1240 const ::rtl::OUString sPropScale = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE);
1241
1242 try
1243 {
1244 const sal_Int32 nCount = xColumns->getCount();
1245 for(sal_Int32 i=0;i<nCount;++i)
1246 {
1247 xColumns->getByIndex(i) >>= xCol;
1248 OSL_ENSURE(xCol.is(),"This should be a column!");
1249
1250 char cTyp( 'C' );
1251
1252 xCol->getPropertyValue(sPropName) >>= aName;
1253
1254 ::rtl::OString aCol;
1255 if ( DBTypeConversion::convertUnicodeString( aName, aCol, m_eEncoding ) > nMaxFieldLength)
1256 {
1257 throwInvalidColumnType( STR_INVALID_COLUMN_NAME_LENGTH, aName );
1258 }
1259
1260 (*m_pFileStream) << aCol.getStr();
1261 m_pFileStream->Write(aBuffer, 11 - aCol.getLength());
1262
1263 sal_Int32 nPrecision = 0;
1264 xCol->getPropertyValue(sPropPrec) >>= nPrecision;
1265 sal_Int32 nScale = 0;
1266 xCol->getPropertyValue(sPropScale) >>= nScale;
1267
1268 bool bBinary = false;
1269
1270 switch (getINT32(xCol->getPropertyValue(sPropType)))
1271 {
1272 case DataType::CHAR:
1273 case DataType::VARCHAR:
1274 cTyp = 'C';
1275 break;
1276 case DataType::DOUBLE:
1277 if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency wird gesondert behandelt
1278 cTyp = 'Y';
1279 else
1280 cTyp = 'B';
1281 break;
1282 case DataType::INTEGER:
1283 cTyp = 'I';
1284 break;
1285 case DataType::TINYINT:
1286 case DataType::SMALLINT:
1287 case DataType::BIGINT:
1288 case DataType::DECIMAL:
1289 case DataType::NUMERIC:
1290 case DataType::REAL:
1291 cTyp = 'N'; // nur dBase 3 format
1292 break;
1293 case DataType::TIMESTAMP:
1294 cTyp = 'T';
1295 break;
1296 case DataType::DATE:
1297 cTyp = 'D';
1298 break;
1299 case DataType::BIT:
1300 cTyp = 'L';
1301 break;
1302 case DataType::LONGVARBINARY:
1303 bBinary = true;
1304 // run through
1305 case DataType::LONGVARCHAR:
1306 cTyp = 'M';
1307 break;
1308 default:
1309 {
1310 throwInvalidColumnType(STR_INVALID_COLUMN_TYPE, aName);
1311 }
1312 }
1313
1314 (*m_pFileStream) << cTyp;
1315 if ( nDbaseType == VisualFoxPro )
1316 (*m_pFileStream) << (nRecLength-1);
1317 else
1318 m_pFileStream->Write(aBuffer, 4);
1319
1320 switch(cTyp)
1321 {
1322 case 'C':
1323 OSL_ENSURE(nPrecision < 255, "ODbaseTable::Create: Column zu lang!");
1324 if (nPrecision > 254)
1325 {
1326 throwInvalidColumnType(STR_INVALID_COLUMN_PRECISION, aName);
1327 }
1328 (*m_pFileStream) << (sal_uInt8) Min((sal_uIntPtr)nPrecision, 255UL); //Feldlaenge
1329 nRecLength = nRecLength + (sal_uInt16)::std::min((sal_uInt16)nPrecision, (sal_uInt16)255UL);
1330 (*m_pFileStream) << (sal_uInt8)0; //Nachkommastellen
1331 break;
1332 case 'F':
1333 case 'N':
1334 OSL_ENSURE(nPrecision >= nScale,
1335 "ODbaseTable::Create: Feldlaenge muss groesser Nachkommastellen sein!");
1336 if (nPrecision < nScale)
1337 {
1338 throwInvalidColumnType(STR_INVALID_PRECISION_SCALE, aName);
1339 }
1340 if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency wird gesondert behandelt
1341 {
1342 (*m_pFileStream) << (sal_uInt8)10; // Standard Laenge
1343 (*m_pFileStream) << (sal_uInt8)4;
1344 nRecLength += 10;
1345 }
1346 else
1347 {
1348 sal_Int32 nPrec = SvDbaseConverter::ConvertPrecisionToDbase(nPrecision,nScale);
1349
1350 (*m_pFileStream) << (sal_uInt8)( nPrec);
1351 (*m_pFileStream) << (sal_uInt8)nScale;
1352 nRecLength += (sal_uInt16)nPrec;
1353 }
1354 break;
1355 case 'L':
1356 (*m_pFileStream) << (sal_uInt8)1;
1357 (*m_pFileStream) << (sal_uInt8)0;
1358 ++nRecLength;
1359 break;
1360 case 'I':
1361 (*m_pFileStream) << (sal_uInt8)4;
1362 (*m_pFileStream) << (sal_uInt8)0;
1363 nRecLength += 4;
1364 break;
1365 case 'Y':
1366 case 'B':
1367 case 'T':
1368 case 'D':
1369 (*m_pFileStream) << (sal_uInt8)8;
1370 (*m_pFileStream) << (sal_uInt8)0;
1371 nRecLength += 8;
1372 break;
1373 case 'M':
1374 bCreateMemo = sal_True;
1375 (*m_pFileStream) << (sal_uInt8)10;
1376 (*m_pFileStream) << (sal_uInt8)0;
1377 nRecLength += 10;
1378 if ( bBinary )
1379 aBuffer[0] = 0x06;
1380 break;
1381 default:
1382 throwInvalidColumnType(STR_INVALID_COLUMN_TYPE, aName);
1383 }
1384 m_pFileStream->Write(aBuffer, 14);
1385 aBuffer[0] = 0x00;
1386 }
1387
1388 (*m_pFileStream) << (sal_uInt8)FIELD_DESCRIPTOR_TERMINATOR; // kopf ende
1389 (*m_pFileStream) << (char)DBF_EOL;
1390 m_pFileStream->Seek(10L);
1391 (*m_pFileStream) << nRecLength; // Satzlaenge nachtraeglich eintragen
1392
1393 if (bCreateMemo)
1394 {
1395 m_pFileStream->Seek(0L);
1396 if (nDbaseType == VisualFoxPro)
1397 (*m_pFileStream) << (sal_uInt8) FoxProMemo;
1398 else
1399 (*m_pFileStream) << (sal_uInt8) dBaseIIIMemo;
1400 } // if (bCreateMemo)
1401 }
1402 catch ( const Exception& e )
1403 {
1404 (void)e;
1405
1406 try
1407 {
1408 // we have to drop the file because it is corrupted now
1409 DropImpl();
1410 }
1411 catch(const Exception&) { }
1412 throw;
1413 }
1414 return sal_True;
1415 }
1416
1417 //------------------------------------------------------------------
1418 // erzeugt grundsaetzlich dBase III Datei Format
CreateMemoFile(const INetURLObject & aFile)1419 sal_Bool ODbaseTable::CreateMemoFile(const INetURLObject& aFile)
1420 {
1421 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::CreateMemoFile" );
1422 // Makro zum Filehandling fuers Erzeugen von Tabellen
1423 m_pMemoStream = createStream_simpleError( aFile.GetMainURL(INetURLObject::NO_DECODE),STREAM_READWRITE | STREAM_SHARE_DENYWRITE);
1424
1425 if (!m_pMemoStream)
1426 return sal_False;
1427
1428 char aBuffer[512]; // write buffer
1429 memset(aBuffer,0,sizeof(aBuffer));
1430
1431 m_pMemoStream->SetFiller('\0');
1432 m_pMemoStream->SetStreamSize(512);
1433
1434 m_pMemoStream->Seek(0L);
1435 (*m_pMemoStream) << long(1); // Zeiger auf ersten freien Block
1436
1437 m_pMemoStream->Flush();
1438 delete m_pMemoStream;
1439 m_pMemoStream = NULL;
1440 return sal_True;
1441 }
1442 //------------------------------------------------------------------
Drop_Static(const::rtl::OUString & _sUrl,sal_Bool _bHasMemoFields,OCollection * _pIndexes)1443 sal_Bool ODbaseTable::Drop_Static(const ::rtl::OUString& _sUrl,sal_Bool _bHasMemoFields,OCollection* _pIndexes )
1444 {
1445 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::Drop_Static" );
1446 INetURLObject aURL;
1447 aURL.SetURL(_sUrl);
1448
1449 sal_Bool bDropped = ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::NO_DECODE));
1450
1451 if(bDropped)
1452 {
1453 if (_bHasMemoFields)
1454 { // delete the memo fields
1455 aURL.setExtension(String::CreateFromAscii("dbt"));
1456 bDropped = ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::NO_DECODE));
1457 }
1458
1459 if(bDropped)
1460 {
1461 if(_pIndexes)
1462 {
1463 try
1464 {
1465 sal_Int32 i = _pIndexes->getCount();
1466 while (i)
1467 {
1468 _pIndexes->dropByIndex(--i);
1469 }
1470 }
1471 catch(SQLException)
1472 {
1473 }
1474 }
1475 // aFile.SetBase(m_Name);
1476 aURL.setExtension(String::CreateFromAscii("inf"));
1477
1478 // as the inf file does not necessarily exist, we aren't allowed to use UCBContentHelper::Kill
1479 // 89711 - 16.07.2001 - frank.schoenheit@sun.com
1480 try
1481 {
1482 ::ucbhelper::Content aDeleteContent( aURL.GetMainURL( INetURLObject::NO_DECODE ), Reference< XCommandEnvironment > () );
1483 aDeleteContent.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) );
1484 }
1485 catch(Exception&)
1486 {
1487 // silently ignore this ....
1488 }
1489 }
1490 }
1491 return bDropped;
1492 }
1493 // -----------------------------------------------------------------------------
DropImpl()1494 sal_Bool ODbaseTable::DropImpl()
1495 {
1496 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::DropImpl" );
1497 FileClose();
1498
1499 if(!m_pIndexes)
1500 refreshIndexes(); // look for indexes which must be deleted as well
1501
1502 sal_Bool bDropped = Drop_Static(getEntry(m_pConnection,m_Name),HasMemoFields(),m_pIndexes);
1503 if(!bDropped)
1504 {// we couldn't drop the table so we have to reopen it
1505 construct();
1506 if(m_pColumns)
1507 m_pColumns->refresh();
1508 }
1509 return bDropped;
1510 }
1511
1512 //------------------------------------------------------------------
InsertRow(OValueRefVector & rRow,sal_Bool bFlush,const Reference<XIndexAccess> & _xCols)1513 sal_Bool ODbaseTable::InsertRow(OValueRefVector& rRow, sal_Bool bFlush,const Reference<XIndexAccess>& _xCols)
1514 {
1515 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::InsertRow" );
1516 // Buffer mit Leerzeichen fuellen
1517 AllocBuffer();
1518 memset(m_pBuffer, 0, m_aHeader.db_slng);
1519 m_pBuffer[0] = ' ';
1520
1521 // Gesamte neue Row uebernehmen:
1522 // ... und am Ende als neuen Record hinzufuegen:
1523 sal_uInt32 nTempPos = m_nFilePos,
1524 nFileSize = 0,
1525 nMemoFileSize = 0;
1526
1527 m_nFilePos = (sal_uIntPtr)m_aHeader.db_anz + 1;
1528 sal_Bool bInsertRow = UpdateBuffer( rRow, NULL, _xCols );
1529 if ( bInsertRow )
1530 {
1531 nFileSize = lcl_getFileSize(*m_pFileStream);
1532
1533 if (HasMemoFields() && m_pMemoStream)
1534 {
1535 m_pMemoStream->Seek(STREAM_SEEK_TO_END);
1536 nMemoFileSize = m_pMemoStream->Tell();
1537 }
1538
1539 if (!WriteBuffer())
1540 {
1541 m_pFileStream->SetStreamSize(nFileSize); // alte Groesse restaurieren
1542
1543 if (HasMemoFields() && m_pMemoStream)
1544 m_pMemoStream->SetStreamSize(nMemoFileSize); // alte Groesse restaurieren
1545 m_nFilePos = nTempPos; // Fileposition restaurieren
1546 }
1547 else
1548 {
1549 (*m_pFileStream) << (char)DBF_EOL; // write EOL
1550 // Anzahl Datensaetze im Header erhoehen:
1551 m_pFileStream->Seek( 4L );
1552 (*m_pFileStream) << (m_aHeader.db_anz + 1);
1553
1554 // beim AppendOnly kein Flush!
1555 if (bFlush)
1556 m_pFileStream->Flush();
1557
1558 // bei Erfolg # erhoehen
1559 m_aHeader.db_anz++;
1560 *rRow.get()[0] = m_nFilePos; // BOOKmark setzen
1561 m_nFilePos = nTempPos;
1562 }
1563 }
1564 else
1565 m_nFilePos = nTempPos;
1566
1567 return bInsertRow;
1568 }
1569
1570 //------------------------------------------------------------------
UpdateRow(OValueRefVector & rRow,OValueRefRow & pOrgRow,const Reference<XIndexAccess> & _xCols)1571 sal_Bool ODbaseTable::UpdateRow(OValueRefVector& rRow, OValueRefRow& pOrgRow,const Reference<XIndexAccess>& _xCols)
1572 {
1573 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::UpdateRow" );
1574 // Buffer mit Leerzeichen fuellen
1575 AllocBuffer();
1576
1577 // Auf gewuenschten Record positionieren:
1578 long nPos = m_aHeader.db_kopf + (long)(m_nFilePos-1) * m_aHeader.db_slng;
1579 m_pFileStream->Seek(nPos);
1580 m_pFileStream->Read((char*)m_pBuffer, m_aHeader.db_slng);
1581
1582 sal_uInt32 nMemoFileSize( 0 );
1583 if (HasMemoFields() && m_pMemoStream)
1584 {
1585 m_pMemoStream->Seek(STREAM_SEEK_TO_END);
1586 nMemoFileSize = m_pMemoStream->Tell();
1587 }
1588 if (!UpdateBuffer(rRow, pOrgRow,_xCols) || !WriteBuffer())
1589 {
1590 if (HasMemoFields() && m_pMemoStream)
1591 m_pMemoStream->SetStreamSize(nMemoFileSize); // alte Groesse restaurieren
1592 }
1593 else
1594 {
1595 m_pFileStream->Flush();
1596 }
1597 return sal_True;
1598 }
1599
1600 //------------------------------------------------------------------
DeleteRow(const OSQLColumns & _rCols)1601 sal_Bool ODbaseTable::DeleteRow(const OSQLColumns& _rCols)
1602 {
1603 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::DeleteRow" );
1604 // Einfach das Loesch-Flag setzen (egal, ob es schon gesetzt war
1605 // oder nicht):
1606 // Auf gewuenschten Record positionieren:
1607 long nFilePos = m_aHeader.db_kopf + (long)(m_nFilePos-1) * m_aHeader.db_slng;
1608 m_pFileStream->Seek(nFilePos);
1609
1610 OValueRefRow aRow = new OValueRefVector(_rCols.get().size());
1611
1612 if (!fetchRow(aRow,_rCols,sal_True,sal_True))
1613 return sal_False;
1614
1615 Reference<XPropertySet> xCol;
1616 ::rtl::OUString aColName;
1617 ::comphelper::UStringMixEqual aCase(isCaseSensitive());
1618 for (sal_uInt16 i = 0; i < m_pColumns->getCount(); i++)
1619 {
1620 Reference<XPropertySet> xIndex = isUniqueByColumnName(i);
1621 if (xIndex.is())
1622 {
1623 ::cppu::extractInterface(xCol,m_pColumns->getByIndex(i));
1624 OSL_ENSURE(xCol.is(),"ODbaseTable::DeleteRow column is null!");
1625 if(xCol.is())
1626 {
1627 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
1628
1629 Reference<XUnoTunnel> xTunnel(xIndex,UNO_QUERY);
1630 OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!");
1631 ODbaseIndex* pIndex = reinterpret_cast< ODbaseIndex* >( xTunnel->getSomething(ODbaseIndex::getUnoTunnelImplementationId()) );
1632 OSL_ENSURE(pIndex,"ODbaseTable::DeleteRow: No Index returned!");
1633
1634 OSQLColumns::Vector::const_iterator aIter = _rCols.get().begin();
1635 sal_Int32 nPos = 1;
1636 for(;aIter != _rCols.get().end();++aIter,++nPos)
1637 {
1638 if(aCase(getString((*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME))),aColName))
1639 break;
1640 }
1641 if (aIter == _rCols.get().end())
1642 continue;
1643
1644 pIndex->Delete(m_nFilePos,*(aRow->get())[nPos]);
1645 }
1646 }
1647 }
1648
1649 m_pFileStream->Seek(nFilePos);
1650 (*m_pFileStream) << (sal_uInt8)'*'; // mark the row in the table as deleted
1651 m_pFileStream->Flush();
1652 return sal_True;
1653 }
1654 // -------------------------------------------------------------------------
isUniqueByColumnName(sal_Int32 _nColumnPos)1655 Reference<XPropertySet> ODbaseTable::isUniqueByColumnName(sal_Int32 _nColumnPos)
1656 {
1657 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::isUniqueByColumnName" );
1658 if(!m_pIndexes)
1659 refreshIndexes();
1660 if(m_pIndexes->hasElements())
1661 {
1662 Reference<XPropertySet> xCol;
1663 m_pColumns->getByIndex(_nColumnPos) >>= xCol;
1664 OSL_ENSURE(xCol.is(),"ODbaseTable::isUniqueByColumnName column is null!");
1665 ::rtl::OUString sColName;
1666 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sColName;
1667
1668 Reference<XPropertySet> xIndex;
1669 for(sal_Int32 i=0;i<m_pIndexes->getCount();++i)
1670 {
1671 ::cppu::extractInterface(xIndex,m_pIndexes->getByIndex(i));
1672 if(xIndex.is() && getBOOL(xIndex->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISUNIQUE))))
1673 {
1674 Reference<XNameAccess> xCols(Reference<XColumnsSupplier>(xIndex,UNO_QUERY)->getColumns());
1675 if(xCols->hasByName(sColName))
1676 return xIndex;
1677
1678 }
1679 }
1680 }
1681 return Reference<XPropertySet>();
1682 }
1683 //------------------------------------------------------------------
toDouble(const ByteString & rString)1684 double toDouble(const ByteString& rString)
1685 {
1686 return ::rtl::math::stringToDouble( rString, '.', ',', NULL, NULL );
1687 }
1688
1689 //------------------------------------------------------------------
UpdateBuffer(OValueRefVector & rRow,OValueRefRow pOrgRow,const Reference<XIndexAccess> & _xCols)1690 sal_Bool ODbaseTable::UpdateBuffer(OValueRefVector& rRow, OValueRefRow pOrgRow,const Reference<XIndexAccess>& _xCols)
1691 {
1692 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::UpdateBuffer" );
1693 OSL_ENSURE(m_pBuffer,"Buffer is NULL!");
1694 if ( !m_pBuffer )
1695 return sal_False;
1696 sal_Int32 nByteOffset = 1;
1697
1698 // Felder aktualisieren:
1699 Reference<XPropertySet> xCol;
1700 Reference<XPropertySet> xIndex;
1701 sal_uInt16 i;
1702 ::rtl::OUString aColName;
1703 const sal_Int32 nColumnCount = m_pColumns->getCount();
1704 ::std::vector< Reference<XPropertySet> > aIndexedCols(nColumnCount);
1705
1706 ::comphelper::UStringMixEqual aCase(isCaseSensitive());
1707
1708 Reference<XIndexAccess> xColumns = m_pColumns;
1709 // first search a key that exist already in the table
1710 for (i = 0; i < nColumnCount; ++i)
1711 {
1712 sal_Int32 nPos = i;
1713 if(_xCols != xColumns)
1714 {
1715 m_pColumns->getByIndex(i) >>= xCol;
1716 OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!");
1717 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
1718
1719 for(nPos = 0;nPos<_xCols->getCount();++nPos)
1720 {
1721 Reference<XPropertySet> xFindCol;
1722 ::cppu::extractInterface(xFindCol,_xCols->getByIndex(nPos));
1723 OSL_ENSURE(xFindCol.is(),"ODbaseTable::UpdateBuffer column is null!");
1724 if(aCase(getString(xFindCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),aColName))
1725 break;
1726 }
1727 if (nPos >= _xCols->getCount())
1728 continue;
1729 }
1730
1731 ++nPos;
1732 xIndex = isUniqueByColumnName(i);
1733 aIndexedCols[i] = xIndex;
1734 if (xIndex.is())
1735 {
1736 // first check if the value is different to the old one and when if it conform to the index
1737 if(pOrgRow.isValid() && (rRow.get()[nPos]->getValue().isNull() || rRow.get()[nPos] == (pOrgRow->get())[nPos]))
1738 continue;
1739 else
1740 {
1741 // ODbVariantRef xVar = (pVal == NULL) ? new ODbVariant() : pVal;
1742 Reference<XUnoTunnel> xTunnel(xIndex,UNO_QUERY);
1743 OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!");
1744 ODbaseIndex* pIndex = reinterpret_cast< ODbaseIndex* >( xTunnel->getSomething(ODbaseIndex::getUnoTunnelImplementationId()) );
1745 OSL_ENSURE(pIndex,"ODbaseTable::UpdateBuffer: No Index returned!");
1746
1747 if (pIndex->Find(0,*rRow.get()[nPos]))
1748 {
1749 // es existiert kein eindeutiger Wert
1750 if ( !aColName.getLength() )
1751 {
1752 m_pColumns->getByIndex(i) >>= xCol;
1753 OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!");
1754 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
1755 xCol.clear();
1756 } // if ( !aColName.getLength() )
1757 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
1758 STR_DUPLICATE_VALUE_IN_COLUMN
1759 ,"$columnname$", aColName
1760 ) );
1761 ::dbtools::throwGenericSQLException( sError, *this );
1762 }
1763 }
1764 }
1765 }
1766
1767 // when we are here there is no double key in the table
1768
1769 for (i = 0; i < nColumnCount && nByteOffset <= m_nBufferSize ; ++i)
1770 {
1771 // Laengen je nach Datentyp:
1772 OSL_ENSURE(i < m_aPrecisions.size(),"Illegal index!");
1773 sal_Int32 nLen = 0;
1774 sal_Int32 nType = 0;
1775 sal_Int32 nScale = 0;
1776 if ( i < m_aPrecisions.size() )
1777 {
1778 nLen = m_aPrecisions[i];
1779 nType = m_aTypes[i];
1780 nScale = m_aScales[i];
1781 }
1782 else
1783 {
1784 m_pColumns->getByIndex(i) >>= xCol;
1785 if ( xCol.is() )
1786 {
1787 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nLen;
1788 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= nType;
1789 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
1790 }
1791 }
1792
1793 bool bSetZero = false;
1794 switch (nType)
1795 {
1796 case DataType::INTEGER:
1797 case DataType::DOUBLE:
1798 case DataType::TIMESTAMP:
1799 bSetZero = true;
1800 case DataType::LONGVARBINARY:
1801 case DataType::DATE:
1802 case DataType::BIT:
1803 case DataType::LONGVARCHAR:
1804 nLen = m_aRealFieldLengths[i];
1805 break;
1806 case DataType::DECIMAL:
1807 nLen = SvDbaseConverter::ConvertPrecisionToDbase(nLen,nScale);
1808 break; // das Vorzeichen und das Komma
1809 default:
1810 break;
1811
1812 } // switch (nType)
1813
1814 sal_Int32 nPos = i;
1815 if(_xCols != xColumns)
1816 {
1817 m_pColumns->getByIndex(i) >>= xCol;
1818 OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!");
1819 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
1820 for(nPos = 0;nPos<_xCols->getCount();++nPos)
1821 {
1822 Reference<XPropertySet> xFindCol;
1823 ::cppu::extractInterface(xFindCol,_xCols->getByIndex(nPos));
1824 if(aCase(getString(xFindCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME))),aColName))
1825 break;
1826 }
1827 if (nPos >= _xCols->getCount())
1828 {
1829 nByteOffset += nLen;
1830 continue;
1831 }
1832 }
1833
1834
1835
1836 ++nPos; // the row values start at 1
1837 // Ist die Variable ueberhaupt gebunden?
1838 if ( !rRow.get()[nPos]->isBound() )
1839 {
1840 // Nein - naechstes Feld.
1841 nByteOffset += nLen;
1842 continue;
1843 }
1844 if (aIndexedCols[i].is())
1845 {
1846 Reference<XUnoTunnel> xTunnel(aIndexedCols[i],UNO_QUERY);
1847 OSL_ENSURE(xTunnel.is(),"No TunnelImplementation!");
1848 ODbaseIndex* pIndex = reinterpret_cast< ODbaseIndex* >( xTunnel->getSomething(ODbaseIndex::getUnoTunnelImplementationId()) );
1849 OSL_ENSURE(pIndex,"ODbaseTable::UpdateBuffer: No Index returned!");
1850 // Update !!
1851 if (pOrgRow.isValid() && !rRow.get()[nPos]->getValue().isNull() )//&& pVal->isModified())
1852 pIndex->Update(m_nFilePos,*(pOrgRow->get())[nPos],*rRow.get()[nPos]);
1853 else
1854 pIndex->Insert(m_nFilePos,*rRow.get()[nPos]);
1855 }
1856
1857 char* pData = (char *)(m_pBuffer + nByteOffset);
1858 if (rRow.get()[nPos]->getValue().isNull())
1859 {
1860 if ( bSetZero )
1861 memset(pData,0,nLen); // Zuruecksetzen auf NULL
1862 else
1863 memset(pData,' ',nLen); // Zuruecksetzen auf NULL
1864 nByteOffset += nLen;
1865 OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
1866 continue;
1867 }
1868
1869 sal_Bool bHadError = sal_False;
1870 try
1871 {
1872 switch (nType)
1873 {
1874 case DataType::TIMESTAMP:
1875 {
1876 sal_Int32 nJulianDate = 0, nJulianTime = 0;
1877 lcl_CalcJulDate(nJulianDate,nJulianTime,rRow.get()[nPos]->getValue());
1878 // Genau 8 Byte kopieren:
1879 memcpy(pData,&nJulianDate,4);
1880 memcpy(pData+4,&nJulianTime,4);
1881 }
1882 break;
1883 case DataType::DATE:
1884 {
1885 ::com::sun::star::util::Date aDate;
1886 if(rRow.get()[nPos]->getValue().getTypeKind() == DataType::DOUBLE)
1887 aDate = ::dbtools::DBTypeConversion::toDate(rRow.get()[nPos]->getValue().getDouble());
1888 else
1889 aDate = rRow.get()[nPos]->getValue();
1890 char s[9];
1891 snprintf(s,
1892 sizeof(s),
1893 "%04d%02d%02d",
1894 (int)aDate.Year,
1895 (int)aDate.Month,
1896 (int)aDate.Day);
1897
1898 // Genau 8 Byte kopieren:
1899 strncpy(pData,s,sizeof s - 1);
1900 } break;
1901 case DataType::INTEGER:
1902 {
1903 sal_Int32 nValue = rRow.get()[nPos]->getValue();
1904 memcpy(pData,&nValue,nLen);
1905 }
1906 break;
1907 case DataType::DOUBLE:
1908 {
1909 const double d = rRow.get()[nPos]->getValue();
1910 m_pColumns->getByIndex(i) >>= xCol;
1911
1912 if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency wird gesondert behandelt
1913 {
1914 sal_Int64 nValue = 0;
1915 if ( m_aScales[i] )
1916 nValue = (sal_Int64)(d * pow(10.0,(int)m_aScales[i]));
1917 else
1918 nValue = (sal_Int64)(d);
1919 memcpy(pData,&nValue,nLen);
1920 } // if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency wird gesondert behandelt
1921 else
1922 memcpy(pData,&d,nLen);
1923 }
1924 break;
1925 case DataType::DECIMAL:
1926 {
1927 memset(pData,' ',nLen); // Zuruecksetzen auf NULL
1928
1929 const double n = rRow.get()[nPos]->getValue();
1930
1931 // ein const_cast, da GetFormatPrecision am SvNumberFormat nicht const ist, obwohl es das eigentlich
1932 // sein koennte und muesste
1933
1934 const ByteString aDefaultValue( ::rtl::math::doubleToString( n, rtl_math_StringFormat_F, nScale, '.', NULL, 0));
1935 sal_Bool bValidLength = aDefaultValue.Len() <= nLen;
1936 if ( bValidLength )
1937 {
1938 strncpy(pData,aDefaultValue.GetBuffer(),nLen);
1939 // write the resulting double back
1940 *rRow.get()[nPos] = toDouble(aDefaultValue);
1941 }
1942 else
1943 {
1944 m_pColumns->getByIndex(i) >>= xCol;
1945 OSL_ENSURE(xCol.is(),"ODbaseTable::UpdateBuffer column is null!");
1946 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
1947 ::std::list< ::std::pair<const sal_Char* , ::rtl::OUString > > aStringToSubstitutes;
1948 aStringToSubstitutes.push_back(::std::pair<const sal_Char* , ::rtl::OUString >("$columnname$", aColName));
1949 aStringToSubstitutes.push_back(::std::pair<const sal_Char* , ::rtl::OUString >("$precision$", String::CreateFromInt32(nLen)));
1950 aStringToSubstitutes.push_back(::std::pair<const sal_Char* , ::rtl::OUString >("$scale$", String::CreateFromInt32(nScale)));
1951 aStringToSubstitutes.push_back(::std::pair<const sal_Char* , ::rtl::OUString >("$value$", ::rtl::OStringToOUString(aDefaultValue,RTL_TEXTENCODING_UTF8)));
1952
1953 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
1954 STR_INVALID_COLUMN_DECIMAL_VALUE
1955 ,aStringToSubstitutes
1956 ) );
1957 ::dbtools::throwGenericSQLException( sError, *this );
1958 }
1959 } break;
1960 case DataType::BIT:
1961 *pData = rRow.get()[nPos]->getValue().getBool() ? 'T' : 'F';
1962 break;
1963 case DataType::LONGVARBINARY:
1964 case DataType::LONGVARCHAR:
1965 {
1966 char cNext = pData[nLen]; // merken und temporaer durch 0 ersetzen
1967 pData[nLen] = '\0'; // das geht, da der Puffer immer ein Zeichen groesser ist ...
1968
1969 sal_uIntPtr nBlockNo = strtol((const char *)pData,NULL,10); // Blocknummer lesen
1970
1971 // Naechstes Anfangszeichen wieder restaurieren:
1972 pData[nLen] = cNext;
1973 if (!m_pMemoStream || !WriteMemo(rRow.get()[nPos]->get(), nBlockNo))
1974 break;
1975
1976 ByteString aStr;
1977 ByteString aBlock(ByteString::CreateFromInt32(nBlockNo));
1978 aStr.Expand(static_cast<sal_uInt16>(nLen - aBlock.Len()), '0' );
1979 aStr += aBlock;
1980 // Zeichen kopieren:
1981 memset(pData,' ',nLen); // Zuruecksetzen auf NULL
1982 memcpy(pData, aStr.GetBuffer(), nLen);
1983 } break;
1984 default:
1985 {
1986 memset(pData,' ',nLen); // Zuruecksetzen auf NULL
1987
1988 ::rtl::OUString sStringToWrite( rRow.get()[nPos]->getValue().getString() );
1989
1990 // convert the string, using the connection's encoding
1991 ::rtl::OString sEncoded;
1992
1993 DBTypeConversion::convertUnicodeStringToLength( sStringToWrite, sEncoded, nLen, m_eEncoding );
1994 memcpy( pData, sEncoded.getStr(), sEncoded.getLength() );
1995
1996 }
1997 break;
1998 }
1999 }
2000 catch( SQLException& )
2001 {
2002 throw;
2003 }
2004 catch ( Exception& ) { bHadError = sal_True; }
2005
2006 if ( bHadError )
2007 {
2008 m_pColumns->getByIndex(i) >>= xCol;
2009 OSL_ENSURE( xCol.is(), "ODbaseTable::UpdateBuffer column is null!" );
2010 if ( xCol.is() )
2011 xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= aColName;
2012
2013 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
2014 STR_INVALID_COLUMN_VALUE,
2015 "$columnname$", aColName
2016 ) );
2017 ::dbtools::throwGenericSQLException( sError, *this );
2018 }
2019 // Und weiter ...
2020 nByteOffset += nLen;
2021 OSL_ENSURE( nByteOffset <= m_nBufferSize ,"ByteOffset > m_nBufferSize!");
2022 }
2023 return sal_True;
2024 }
2025
2026 // -----------------------------------------------------------------------------
WriteMemo(ORowSetValue & aVariable,sal_uIntPtr & rBlockNr)2027 sal_Bool ODbaseTable::WriteMemo(ORowSetValue& aVariable, sal_uIntPtr& rBlockNr)
2028 {
2029 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::WriteMemo" );
2030 // wird die BlockNr 0 vorgegeben, wird der block ans Ende gehaengt
2031 sal_uIntPtr nSize = 0;
2032 ::rtl::OString aStr;
2033 ::com::sun::star::uno::Sequence<sal_Int8> aValue;
2034 sal_uInt8 nHeader[4];
2035 const bool bBinary = aVariable.getTypeKind() == DataType::LONGVARBINARY && m_aMemoHeader.db_typ == MemoFoxPro;
2036 if ( bBinary )
2037 {
2038 aValue = aVariable.getSequence();
2039 nSize = aValue.getLength();
2040 }
2041 else
2042 {
2043 nSize = DBTypeConversion::convertUnicodeString( aVariable.getString(), aStr, m_eEncoding );
2044 }
2045
2046 // Anhaengen oder ueberschreiben
2047 sal_Bool bAppend = rBlockNr == 0;
2048
2049 if (!bAppend)
2050 {
2051 switch (m_aMemoHeader.db_typ)
2052 {
2053 case MemodBaseIII: // dBase III-Memofeld, endet mit 2 * Ctrl-Z
2054 bAppend = nSize > (512 - 2);
2055 break;
2056 case MemoFoxPro:
2057 case MemodBaseIV: // dBase IV-Memofeld mit Laengenangabe
2058 {
2059 char sHeader[4];
2060 m_pMemoStream->Seek(rBlockNr * m_aMemoHeader.db_size);
2061 m_pMemoStream->SeekRel(4L);
2062 m_pMemoStream->Read(sHeader,4);
2063
2064 sal_uIntPtr nOldSize;
2065 if (m_aMemoHeader.db_typ == MemoFoxPro)
2066 nOldSize = ((((unsigned char)sHeader[0]) * 256 +
2067 (unsigned char)sHeader[1]) * 256 +
2068 (unsigned char)sHeader[2]) * 256 +
2069 (unsigned char)sHeader[3];
2070 else
2071 nOldSize = ((((unsigned char)sHeader[3]) * 256 +
2072 (unsigned char)sHeader[2]) * 256 +
2073 (unsigned char)sHeader[1]) * 256 +
2074 (unsigned char)sHeader[0] - 8;
2075
2076 // passt die neue Laenge in die belegten Bloecke
2077 sal_uIntPtr nUsedBlocks = ((nSize + 8) / m_aMemoHeader.db_size) + (((nSize + 8) % m_aMemoHeader.db_size > 0) ? 1 : 0),
2078 nOldUsedBlocks = ((nOldSize + 8) / m_aMemoHeader.db_size) + (((nOldSize + 8) % m_aMemoHeader.db_size > 0) ? 1 : 0);
2079 bAppend = nUsedBlocks > nOldUsedBlocks;
2080 }
2081 }
2082 }
2083
2084 if (bAppend)
2085 {
2086 sal_uIntPtr nStreamSize = m_pMemoStream->Seek(STREAM_SEEK_TO_END);
2087 // letzten block auffuellen
2088 rBlockNr = (nStreamSize / m_aMemoHeader.db_size) + ((nStreamSize % m_aMemoHeader.db_size) > 0 ? 1 : 0);
2089
2090 m_pMemoStream->SetStreamSize(rBlockNr * m_aMemoHeader.db_size);
2091 m_pMemoStream->Seek(STREAM_SEEK_TO_END);
2092 }
2093 else
2094 {
2095 m_pMemoStream->Seek(rBlockNr * m_aMemoHeader.db_size);
2096 }
2097
2098 switch (m_aMemoHeader.db_typ)
2099 {
2100 case MemodBaseIII: // dBase III-Memofeld, endet mit Ctrl-Z
2101 {
2102 const char cEOF = (char) DBF_EOL;
2103 nSize++;
2104 m_pMemoStream->Write( aStr.getStr(), aStr.getLength() );
2105 (*m_pMemoStream) << cEOF << cEOF;
2106 } break;
2107 case MemoFoxPro:
2108 case MemodBaseIV: // dBase IV-Memofeld mit Laengenangabe
2109 {
2110 if ( MemodBaseIV == m_aMemoHeader.db_typ )
2111 (*m_pMemoStream) << (sal_uInt8)0xFF
2112 << (sal_uInt8)0xFF
2113 << (sal_uInt8)0x08;
2114 else
2115 (*m_pMemoStream) << (sal_uInt8)0x00
2116 << (sal_uInt8)0x00
2117 << (sal_uInt8)0x00;
2118
2119 sal_uInt32 nWriteSize = nSize;
2120 if (m_aMemoHeader.db_typ == MemoFoxPro)
2121 {
2122 if ( bBinary )
2123 (*m_pMemoStream) << (sal_uInt8) 0x00; // Picture
2124 else
2125 (*m_pMemoStream) << (sal_uInt8) 0x01; // Memo
2126 for (int i = 4; i > 0; nWriteSize >>= 8)
2127 nHeader[--i] = (sal_uInt8) (nWriteSize % 256);
2128 }
2129 else
2130 {
2131 (*m_pMemoStream) << (sal_uInt8) 0x00;
2132 nWriteSize += 8;
2133 for (int i = 0; i < 4; nWriteSize >>= 8)
2134 nHeader[i++] = (sal_uInt8) (nWriteSize % 256);
2135 }
2136
2137 m_pMemoStream->Write(nHeader,4);
2138 if ( bBinary )
2139 m_pMemoStream->Write( aValue.getConstArray(), aValue.getLength() );
2140 else
2141 m_pMemoStream->Write( aStr.getStr(), aStr.getLength() );
2142 m_pMemoStream->Flush();
2143 }
2144 }
2145
2146
2147 // Schreiben der neuen Blocknummer
2148 if (bAppend)
2149 {
2150 sal_uIntPtr nStreamSize = m_pMemoStream->Seek(STREAM_SEEK_TO_END);
2151 m_aMemoHeader.db_next = (nStreamSize / m_aMemoHeader.db_size) + ((nStreamSize % m_aMemoHeader.db_size) > 0 ? 1 : 0);
2152
2153 // Schreiben der neuen Blocknummer
2154 m_pMemoStream->Seek(0L);
2155 (*m_pMemoStream) << m_aMemoHeader.db_next;
2156 m_pMemoStream->Flush();
2157 }
2158 return sal_True;
2159 }
2160
2161 // -----------------------------------------------------------------------------
2162 // XAlterTable
alterColumnByName(const::rtl::OUString & colName,const Reference<XPropertySet> & descriptor)2163 void SAL_CALL ODbaseTable::alterColumnByName( const ::rtl::OUString& colName, const Reference< XPropertySet >& descriptor ) throw(SQLException, NoSuchElementException, RuntimeException)
2164 {
2165 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::alterColumnByName" );
2166 ::osl::MutexGuard aGuard(m_aMutex);
2167 checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
2168
2169
2170 Reference<XDataDescriptorFactory> xOldColumn;
2171 m_pColumns->getByName(colName) >>= xOldColumn;
2172
2173 alterColumn(m_pColumns->findColumn(colName)-1,descriptor,xOldColumn);
2174 }
2175 // -------------------------------------------------------------------------
alterColumnByIndex(sal_Int32 index,const Reference<XPropertySet> & descriptor)2176 void SAL_CALL ODbaseTable::alterColumnByIndex( sal_Int32 index, const Reference< XPropertySet >& descriptor ) throw(SQLException, ::com::sun::star::lang::IndexOutOfBoundsException, RuntimeException)
2177 {
2178 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::alterColumnByIndex" );
2179 ::osl::MutexGuard aGuard(m_aMutex);
2180 checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
2181
2182 if(index < 0 || index >= m_pColumns->getCount())
2183 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(index),*this);
2184
2185 Reference<XDataDescriptorFactory> xOldColumn;
2186 m_pColumns->getByIndex(index) >>= xOldColumn;
2187 alterColumn(index,descriptor,xOldColumn);
2188 }
2189 // -----------------------------------------------------------------------------
alterColumn(sal_Int32 index,const Reference<XPropertySet> & descriptor,const Reference<XDataDescriptorFactory> & xOldColumn)2190 void ODbaseTable::alterColumn(sal_Int32 index,
2191 const Reference< XPropertySet >& descriptor ,
2192 const Reference< XDataDescriptorFactory >& xOldColumn )
2193 {
2194 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::alterColumn" );
2195 if(index < 0 || index >= m_pColumns->getCount())
2196 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(index),*this);
2197
2198 ODbaseTable* pNewTable = NULL;
2199 try
2200 {
2201 OSL_ENSURE(descriptor.is(),"ODbaseTable::alterColumn: descriptor can not be null!");
2202 // creates a copy of the the original column and copy all properties from descriptor in xCopyColumn
2203 Reference<XPropertySet> xCopyColumn;
2204 if(xOldColumn.is())
2205 xCopyColumn = xOldColumn->createDataDescriptor();
2206 else
2207 xCopyColumn = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2208
2209 ::comphelper::copyProperties(descriptor,xCopyColumn);
2210
2211 // creates a temp file
2212
2213 String sTempName = createTempFile();
2214
2215 pNewTable = new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection));
2216 Reference<XPropertySet> xHoldTable = pNewTable;
2217 pNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),makeAny(::rtl::OUString(sTempName)));
2218 Reference<XAppend> xAppend(pNewTable->getColumns(),UNO_QUERY);
2219 OSL_ENSURE(xAppend.is(),"ODbaseTable::alterColumn: No XAppend interface!");
2220
2221 // copy the structure
2222 sal_Int32 i=0;
2223 for(;i < index;++i)
2224 {
2225 Reference<XPropertySet> xProp;
2226 m_pColumns->getByIndex(i) >>= xProp;
2227 Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
2228 Reference<XPropertySet> xCpy;
2229 if(xColumn.is())
2230 xCpy = xColumn->createDataDescriptor();
2231 else
2232 xCpy = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2233 ::comphelper::copyProperties(xProp,xCpy);
2234 xAppend->appendByDescriptor(xCpy);
2235 }
2236 ++i; // now insert our new column
2237 xAppend->appendByDescriptor(xCopyColumn);
2238
2239 for(;i < m_pColumns->getCount();++i)
2240 {
2241 Reference<XPropertySet> xProp;
2242 m_pColumns->getByIndex(i) >>= xProp;
2243 Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
2244 Reference<XPropertySet> xCpy;
2245 if(xColumn.is())
2246 xCpy = xColumn->createDataDescriptor();
2247 else
2248 xCpy = new OColumn(getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers());
2249 ::comphelper::copyProperties(xProp,xCpy);
2250 xAppend->appendByDescriptor(xCpy);
2251 }
2252
2253 // construct the new table
2254 if(!pNewTable->CreateImpl())
2255 {
2256 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
2257 STR_COLUMN_NOT_ALTERABLE,
2258 "$columnname$", ::comphelper::getString(descriptor->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))
2259 ) );
2260 ::dbtools::throwGenericSQLException( sError, *this );
2261 }
2262
2263 pNewTable->construct();
2264
2265 // copy the data
2266 copyData(pNewTable,0);
2267
2268 // now drop the old one
2269 if( DropImpl() ) // we don't want to delete the memo columns too
2270 {
2271 // rename the new one to the old one
2272 pNewTable->renameImpl(m_Name);
2273 // release the temp file
2274 pNewTable = NULL;
2275 ::comphelper::disposeComponent(xHoldTable);
2276 }
2277 else
2278 {
2279 pNewTable = NULL;
2280 }
2281 FileClose();
2282 construct();
2283 if(m_pColumns)
2284 m_pColumns->refresh();
2285
2286 }
2287 catch(const SQLException&)
2288 {
2289 throw;
2290 }
2291 catch(const Exception&)
2292 {
2293 OSL_ENSURE(0,"ODbaseTable::alterColumn: Exception occured!");
2294 throw;
2295 }
2296 }
2297 // -----------------------------------------------------------------------------
getMetaData() const2298 Reference< XDatabaseMetaData> ODbaseTable::getMetaData() const
2299 {
2300 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getMetaData" );
2301 return getConnection()->getMetaData();
2302 }
2303 // -------------------------------------------------------------------------
rename(const::rtl::OUString & newName)2304 void SAL_CALL ODbaseTable::rename( const ::rtl::OUString& newName ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException)
2305 {
2306 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::rename" );
2307 ::osl::MutexGuard aGuard(m_aMutex);
2308 checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
2309 if(m_pTables && m_pTables->hasByName(newName))
2310 throw ElementExistException(newName,*this);
2311
2312
2313 renameImpl(newName);
2314
2315 ODbaseTable_BASE::rename(newName);
2316
2317 construct();
2318 if(m_pColumns)
2319 m_pColumns->refresh();
2320 }
2321 namespace
2322 {
renameFile(OConnection * _pConenction,const::rtl::OUString & oldName,const::rtl::OUString & newName,const String & _sExtension)2323 void renameFile(OConnection* _pConenction,const ::rtl::OUString& oldName,
2324 const ::rtl::OUString& newName,const String& _sExtension)
2325 {
2326 String aName = ODbaseTable::getEntry(_pConenction,oldName);
2327 if(!aName.Len())
2328 {
2329 ::rtl::OUString aIdent = _pConenction->getContent()->getIdentifier()->getContentIdentifier();
2330 if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) )
2331 aIdent += ::rtl::OUString::createFromAscii("/");
2332 aIdent += oldName;
2333 aName = aIdent;
2334 }
2335 INetURLObject aURL;
2336 aURL.SetURL(aName);
2337
2338 aURL.setExtension( _sExtension );
2339 String sNewName(newName);
2340 sNewName.AppendAscii(".");
2341 sNewName += _sExtension;
2342
2343 try
2344 {
2345 Content aContent(aURL.GetMainURL(INetURLObject::NO_DECODE),Reference<XCommandEnvironment>());
2346
2347 Sequence< PropertyValue > aProps( 1 );
2348 aProps[0].Name = ::rtl::OUString::createFromAscii("Title");
2349 aProps[0].Handle = -1; // n/a
2350 aProps[0].Value = makeAny( ::rtl::OUString(sNewName) );
2351 Sequence< Any > aValues;
2352 aContent.executeCommand( rtl::OUString::createFromAscii( "setPropertyValues" ),makeAny(aProps) ) >>= aValues;
2353 if(aValues.getLength() && aValues[0].hasValue())
2354 throw Exception();
2355 }
2356 catch(Exception&)
2357 {
2358 throw ElementExistException(newName,NULL);
2359 }
2360 }
2361 }
2362 // -------------------------------------------------------------------------
renameImpl(const::rtl::OUString & newName)2363 void SAL_CALL ODbaseTable::renameImpl( const ::rtl::OUString& newName ) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::container::ElementExistException, ::com::sun::star::uno::RuntimeException)
2364 {
2365 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getEntry" );
2366 ::osl::MutexGuard aGuard(m_aMutex);
2367
2368 FileClose();
2369
2370
2371 renameFile(m_pConnection,m_Name,newName,m_pConnection->getExtension());
2372 if ( HasMemoFields() )
2373 { // delete the memo fields
2374 String sExt = String::CreateFromAscii("dbt");
2375 renameFile(m_pConnection,m_Name,newName,sExt);
2376 }
2377 }
2378 // -----------------------------------------------------------------------------
addColumn(const Reference<XPropertySet> & _xNewColumn)2379 void ODbaseTable::addColumn(const Reference< XPropertySet >& _xNewColumn)
2380 {
2381 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::addColumn" );
2382 String sTempName = createTempFile();
2383
2384 ODbaseTable* pNewTable = new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection));
2385 Reference< XPropertySet > xHold = pNewTable;
2386 pNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),makeAny(::rtl::OUString(sTempName)));
2387 {
2388 Reference<XAppend> xAppend(pNewTable->getColumns(),UNO_QUERY);
2389 sal_Bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
2390 // copy the structure
2391 for(sal_Int32 i=0;i < m_pColumns->getCount();++i)
2392 {
2393 Reference<XPropertySet> xProp;
2394 m_pColumns->getByIndex(i) >>= xProp;
2395 Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
2396 Reference<XPropertySet> xCpy;
2397 if(xColumn.is())
2398 xCpy = xColumn->createDataDescriptor();
2399 else
2400 {
2401 xCpy = new OColumn(bCase);
2402 ::comphelper::copyProperties(xProp,xCpy);
2403 }
2404
2405 xAppend->appendByDescriptor(xCpy);
2406 }
2407 Reference<XPropertySet> xCpy = new OColumn(bCase);
2408 ::comphelper::copyProperties(_xNewColumn,xCpy);
2409 xAppend->appendByDescriptor(xCpy);
2410 }
2411
2412 // construct the new table
2413 if(!pNewTable->CreateImpl())
2414 {
2415 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
2416 STR_COLUMN_NOT_ADDABLE,
2417 "$columnname$", ::comphelper::getString(_xNewColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))
2418 ) );
2419 ::dbtools::throwGenericSQLException( sError, *this );
2420 }
2421
2422 sal_Bool bAlreadyDroped = sal_False;
2423 try
2424 {
2425 pNewTable->construct();
2426 // copy the data
2427 copyData(pNewTable,pNewTable->m_pColumns->getCount());
2428 // drop the old table
2429 if(DropImpl())
2430 {
2431 bAlreadyDroped = sal_True;
2432 pNewTable->renameImpl(m_Name);
2433 // release the temp file
2434 }
2435 xHold = pNewTable = NULL;
2436
2437 FileClose();
2438 construct();
2439 if(m_pColumns)
2440 m_pColumns->refresh();
2441 }
2442 catch(const SQLException&)
2443 {
2444 // here we know that the old table wasn't droped before
2445 if(!bAlreadyDroped)
2446 xHold = pNewTable = NULL;
2447
2448 throw;
2449 }
2450 }
2451 // -----------------------------------------------------------------------------
dropColumn(sal_Int32 _nPos)2452 void ODbaseTable::dropColumn(sal_Int32 _nPos)
2453 {
2454 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::dropColumn" );
2455 String sTempName = createTempFile();
2456
2457 ODbaseTable* pNewTable = new ODbaseTable(m_pTables,static_cast<ODbaseConnection*>(m_pConnection));
2458 Reference< XPropertySet > xHold = pNewTable;
2459 pNewTable->setPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME),makeAny(::rtl::OUString(sTempName)));
2460 {
2461 Reference<XAppend> xAppend(pNewTable->getColumns(),UNO_QUERY);
2462 sal_Bool bCase = getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers();
2463 // copy the structure
2464 for(sal_Int32 i=0;i < m_pColumns->getCount();++i)
2465 {
2466 if(_nPos != i)
2467 {
2468 Reference<XPropertySet> xProp;
2469 m_pColumns->getByIndex(i) >>= xProp;
2470 Reference<XDataDescriptorFactory> xColumn(xProp,UNO_QUERY);
2471 Reference<XPropertySet> xCpy;
2472 if(xColumn.is())
2473 xCpy = xColumn->createDataDescriptor();
2474 else
2475 {
2476 xCpy = new OColumn(bCase);
2477 ::comphelper::copyProperties(xProp,xCpy);
2478 }
2479 xAppend->appendByDescriptor(xCpy);
2480 }
2481 }
2482 }
2483
2484 // construct the new table
2485 if(!pNewTable->CreateImpl())
2486 {
2487 xHold = pNewTable = NULL;
2488 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
2489 STR_COLUMN_NOT_DROP,
2490 "$position$", ::rtl::OUString::valueOf(_nPos)
2491 ) );
2492 ::dbtools::throwGenericSQLException( sError, *this );
2493 }
2494 pNewTable->construct();
2495 // copy the data
2496 copyData(pNewTable,_nPos);
2497 // drop the old table
2498 if(DropImpl())
2499 pNewTable->renameImpl(m_Name);
2500 // release the temp file
2501
2502 xHold = pNewTable = NULL;
2503
2504 FileClose();
2505 construct();
2506 }
2507 // -----------------------------------------------------------------------------
createTempFile()2508 String ODbaseTable::createTempFile()
2509 {
2510 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::createTempFile" );
2511 ::rtl::OUString aIdent = m_pConnection->getContent()->getIdentifier()->getContentIdentifier();
2512 if ( aIdent.lastIndexOf('/') != (aIdent.getLength()-1) )
2513 aIdent += ::rtl::OUString::createFromAscii("/");
2514 String sTempName(aIdent);
2515 String sExt;
2516 sExt.AssignAscii(".");
2517 sExt += m_pConnection->getExtension();
2518
2519 String sName(m_Name);
2520 TempFile aTempFile(sName,&sExt,&sTempName);
2521 if(!aTempFile.IsValid())
2522 getConnection()->throwGenericSQLException(STR_COULD_NOT_ALTER_TABLE,*this);
2523
2524 INetURLObject aURL;
2525 aURL.SetSmartProtocol(INET_PROT_FILE);
2526 aURL.SetURL(aTempFile.GetURL());
2527
2528 String sNewName(aURL.getName());
2529 sNewName.Erase(sNewName.Len() - sExt.Len());
2530 return sNewName;
2531 }
2532 // -----------------------------------------------------------------------------
copyData(ODbaseTable * _pNewTable,sal_Int32 _nPos)2533 void ODbaseTable::copyData(ODbaseTable* _pNewTable,sal_Int32 _nPos)
2534 {
2535 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::copyData" );
2536 sal_Int32 nPos = _nPos + 1; // +1 because we always have the bookmark clumn as well
2537 OValueRefRow aRow = new OValueRefVector(m_pColumns->getCount());
2538 OValueRefRow aInsertRow;
2539 if(_nPos)
2540 {
2541 aInsertRow = new OValueRefVector(_pNewTable->m_pColumns->getCount());
2542 ::std::for_each(aInsertRow->get().begin(),aInsertRow->get().end(),TSetRefBound(sal_True));
2543 }
2544 else
2545 aInsertRow = aRow;
2546
2547 // we only have to bind the values which we need to copy into the new table
2548 ::std::for_each(aRow->get().begin(),aRow->get().end(),TSetRefBound(sal_True));
2549 if(_nPos && (_nPos < (sal_Int32)aRow->get().size()))
2550 (aRow->get())[nPos]->setBound(sal_False);
2551
2552
2553 sal_Bool bOk = sal_True;
2554 sal_Int32 nCurPos;
2555 OValueRefVector::Vector::iterator aIter;
2556 for(sal_uInt32 nRowPos = 0; nRowPos < m_aHeader.db_anz;++nRowPos)
2557 {
2558 bOk = seekRow( IResultSetHelper::BOOKMARK, nRowPos+1, nCurPos );
2559 if ( bOk )
2560 {
2561 bOk = fetchRow( aRow, m_aColumns.getBody(), sal_True, sal_True);
2562 if ( bOk && !aRow->isDeleted() ) // copy only not deleted rows
2563 {
2564 // special handling when pos == 0 then we don't have to distinguish between the two rows
2565 if(_nPos)
2566 {
2567 aIter = aRow->get().begin()+1;
2568 sal_Int32 nCount = 1;
2569 for(OValueRefVector::Vector::iterator aInsertIter = aInsertRow->get().begin()+1; aIter != aRow->get().end() && aInsertIter != aInsertRow->get().end();++aIter,++nCount)
2570 {
2571 if(nPos != nCount)
2572 {
2573 (*aInsertIter)->setValue( (*aIter)->getValue() );
2574 ++aInsertIter;
2575 }
2576 }
2577 }
2578 bOk = _pNewTable->InsertRow(*aInsertRow,sal_True,_pNewTable->m_pColumns);
2579 OSL_ENSURE(bOk,"Row could not be inserted!");
2580 }
2581 else
2582 OSL_ENSURE(bOk,"Row could not be fetched!");
2583 }
2584 else
2585 {
2586 OSL_ASSERT(0);
2587 }
2588 } // for(sal_uInt32 nRowPos = 0; nRowPos < m_aHeader.db_anz;++nRowPos)
2589 }
2590 // -----------------------------------------------------------------------------
throwInvalidDbaseFormat()2591 void ODbaseTable::throwInvalidDbaseFormat()
2592 {
2593 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::throwInvalidDbaseFormat" );
2594 FileClose();
2595 // no dbase file
2596
2597 const ::rtl::OUString sError( getConnection()->getResources().getResourceStringWithSubstitution(
2598 STR_INVALID_DBASE_FILE,
2599 "$filename$", getEntry(m_pConnection,m_Name)
2600 ) );
2601 ::dbtools::throwGenericSQLException( sError, *this );
2602 }
2603 // -----------------------------------------------------------------------------
refreshHeader()2604 void ODbaseTable::refreshHeader()
2605 {
2606 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::refreshHeader" );
2607 if ( m_aHeader.db_anz == 0 )
2608 readHeader();
2609 }
2610 //------------------------------------------------------------------
seekRow(IResultSetHelper::Movement eCursorPosition,sal_Int32 nOffset,sal_Int32 & nCurPos)2611 sal_Bool ODbaseTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos)
2612 {
2613 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::seekRow" );
2614 // ----------------------------------------------------------
2615 // Positionierung vorbereiten:
2616 OSL_ENSURE(m_pFileStream,"ODbaseTable::seekRow: FileStream is NULL!");
2617
2618 sal_uInt32 nNumberOfRecords = (sal_uInt32)m_aHeader.db_anz;
2619 sal_uInt32 nTempPos = m_nFilePos;
2620 m_nFilePos = nCurPos;
2621
2622 switch(eCursorPosition)
2623 {
2624 case IResultSetHelper::NEXT:
2625 ++m_nFilePos;
2626 break;
2627 case IResultSetHelper::PRIOR:
2628 if (m_nFilePos > 0)
2629 --m_nFilePos;
2630 break;
2631 case IResultSetHelper::FIRST:
2632 m_nFilePos = 1;
2633 break;
2634 case IResultSetHelper::LAST:
2635 m_nFilePos = nNumberOfRecords;
2636 break;
2637 case IResultSetHelper::RELATIVE:
2638 m_nFilePos = (((sal_Int32)m_nFilePos) + nOffset < 0) ? 0L
2639 : (sal_uInt32)(((sal_Int32)m_nFilePos) + nOffset);
2640 break;
2641 case IResultSetHelper::ABSOLUTE:
2642 case IResultSetHelper::BOOKMARK:
2643 m_nFilePos = (sal_uInt32)nOffset;
2644 break;
2645 }
2646
2647 if (m_nFilePos > (sal_Int32)nNumberOfRecords)
2648 m_nFilePos = (sal_Int32)nNumberOfRecords + 1;
2649
2650 if (m_nFilePos == 0 || m_nFilePos == (sal_Int32)nNumberOfRecords + 1)
2651 goto Error;
2652 else
2653 {
2654 sal_uInt16 nEntryLen = m_aHeader.db_slng;
2655
2656 OSL_ENSURE(m_nFilePos >= 1,"SdbDBFCursor::FileFetchRow: ungueltige Record-Position");
2657 sal_Int32 nPos = m_aHeader.db_kopf + (sal_Int32)(m_nFilePos-1) * nEntryLen;
2658
2659 sal_uIntPtr nLen = m_pFileStream->Seek(nPos);
2660 if (m_pFileStream->GetError() != ERRCODE_NONE)
2661 goto Error;
2662
2663 nLen = m_pFileStream->Read((char*)m_pBuffer, nEntryLen);
2664 if (m_pFileStream->GetError() != ERRCODE_NONE)
2665 goto Error;
2666 }
2667 goto End;
2668
2669 Error:
2670 switch(eCursorPosition)
2671 {
2672 case IResultSetHelper::PRIOR:
2673 case IResultSetHelper::FIRST:
2674 m_nFilePos = 0;
2675 break;
2676 case IResultSetHelper::LAST:
2677 case IResultSetHelper::NEXT:
2678 case IResultSetHelper::ABSOLUTE:
2679 case IResultSetHelper::RELATIVE:
2680 if (nOffset > 0)
2681 m_nFilePos = nNumberOfRecords + 1;
2682 else if (nOffset < 0)
2683 m_nFilePos = 0;
2684 break;
2685 case IResultSetHelper::BOOKMARK:
2686 m_nFilePos = nTempPos; // vorherige Position
2687 }
2688 // aStatus.Set(SDB_STAT_NO_DATA_FOUND);
2689 return sal_False;
2690
2691 End:
2692 nCurPos = m_nFilePos;
2693 return sal_True;
2694 }
2695 // -----------------------------------------------------------------------------
ReadMemo(sal_uIntPtr nBlockNo,ORowSetValue & aVariable)2696 sal_Bool ODbaseTable::ReadMemo(sal_uIntPtr nBlockNo, ORowSetValue& aVariable)
2697 {
2698 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::ReadMemo" );
2699 sal_Bool bIsText = sal_True;
2700 // SdbConnection* pConnection = GetConnection();
2701
2702 m_pMemoStream->Seek(nBlockNo * m_aMemoHeader.db_size);
2703 switch (m_aMemoHeader.db_typ)
2704 {
2705 case MemodBaseIII: // dBase III-Memofeld, endet mit Ctrl-Z
2706 {
2707 const char cEOF = (char) DBF_EOL;
2708 ByteString aBStr;
2709 static char aBuf[514];
2710 aBuf[512] = 0; // sonst kann der Zufall uebel mitspielen
2711 sal_Bool bReady = sal_False;
2712
2713 do
2714 {
2715 m_pMemoStream->Read(&aBuf,512);
2716
2717 sal_uInt16 i = 0;
2718 while (aBuf[i] != cEOF && ++i < 512)
2719 ;
2720 bReady = aBuf[i] == cEOF;
2721
2722 aBuf[i] = 0;
2723 aBStr += aBuf;
2724
2725 } while (!bReady && !m_pMemoStream->IsEof() && aBStr.Len() < STRING_MAXLEN);
2726
2727 ::rtl::OUString aStr(aBStr.GetBuffer(), aBStr.Len(),m_eEncoding);
2728 aVariable = aStr;
2729
2730 } break;
2731 case MemoFoxPro:
2732 case MemodBaseIV: // dBase IV-Memofeld mit Laengenangabe
2733 {
2734 char sHeader[4];
2735 m_pMemoStream->Read(sHeader,4);
2736 // Foxpro stores text and binary data
2737 if (m_aMemoHeader.db_typ == MemoFoxPro)
2738 {
2739 // if (((sal_uInt8)sHeader[0]) != 0 || ((sal_uInt8)sHeader[1]) != 0 || ((sal_uInt8)sHeader[2]) != 0)
2740 // {
2741 //// String aText = String(SdbResId(STR_STAT_IResultSetHelper::INVALID));
2742 //// aText.SearchAndReplace(String::CreateFromAscii("%%d"),m_pMemoStream->GetFileName());
2743 //// aText.SearchAndReplace(String::CreateFromAscii("%%t"),aStatus.TypeToString(MEMO));
2744 //// aStatus.Set(SDB_STAT_ERROR,
2745 //// String::CreateFromAscii("01000"),
2746 //// aStatus.CreateErrorMessage(aText),
2747 //// 0, String() );
2748 // return sal_False;
2749 // }
2750 //
2751 bIsText = sHeader[3] != 0;
2752 }
2753 else if (((sal_uInt8)sHeader[0]) != 0xFF || ((sal_uInt8)sHeader[1]) != 0xFF || ((sal_uInt8)sHeader[2]) != 0x08)
2754 {
2755 // String aText = String(SdbResId(STR_STAT_IResultSetHelper::INVALID));
2756 // aText.SearchAndReplace(String::CreateFromAscii("%%d"),m_pMemoStream->GetFileName());
2757 // aText.SearchAndReplace(String::CreateFromAscii("%%t"),aStatus.TypeToString(MEMO));
2758 // aStatus.Set(SDB_STAT_ERROR,
2759 // String::CreateFromAscii("01000"),
2760 // aStatus.CreateErrorMessage(aText),
2761 // 0, String() );
2762 return sal_False;
2763 }
2764
2765 sal_uInt32 nLength(0);
2766 (*m_pMemoStream) >> nLength;
2767
2768 if (m_aMemoHeader.db_typ == MemodBaseIV)
2769 nLength -= 8;
2770
2771 if ( nLength )
2772 {
2773 if ( bIsText )
2774 {
2775 // char cChar;
2776 ::rtl::OUStringBuffer aStr;
2777 while ( nLength > STRING_MAXLEN )
2778 {
2779 ByteString aBStr;
2780 aBStr.Expand(STRING_MAXLEN);
2781 m_pMemoStream->Read(aBStr.AllocBuffer(STRING_MAXLEN),STRING_MAXLEN);
2782 aStr.append(::rtl::OUString(aBStr.GetBuffer(),aBStr.Len(), m_eEncoding));
2783 nLength -= STRING_MAXLEN;
2784 }
2785 if ( nLength > 0 )
2786 {
2787 ByteString aBStr;
2788 aBStr.Expand(static_cast<xub_StrLen>(nLength));
2789 m_pMemoStream->Read(aBStr.AllocBuffer(static_cast<xub_StrLen>(nLength)),nLength);
2790 // aBStr.ReleaseBufferAccess();
2791 aStr.append(::rtl::OUString(aBStr.GetBuffer(),aBStr.Len(), m_eEncoding));
2792 }
2793 if ( aStr.getLength() )
2794 aVariable = aStr.makeStringAndClear();
2795 } // if ( bIsText )
2796 else
2797 {
2798 ::com::sun::star::uno::Sequence< sal_Int8 > aData(nLength);
2799 m_pMemoStream->Read(aData.getArray(),nLength);
2800 aVariable = aData;
2801 }
2802 } // if ( nLength )
2803 }
2804 }
2805 return sal_True;
2806 }
2807 // -----------------------------------------------------------------------------
AllocBuffer()2808 void ODbaseTable::AllocBuffer()
2809 {
2810 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::AllocBuffer" );
2811 sal_uInt16 nSize = m_aHeader.db_slng;
2812 OSL_ENSURE(nSize > 0, "Size too small");
2813
2814 if (m_nBufferSize != nSize)
2815 {
2816 delete m_pBuffer;
2817 m_pBuffer = NULL;
2818 }
2819
2820 // Falls noch kein Puffer vorhanden: allozieren:
2821 if (m_pBuffer == NULL && nSize > 0)
2822 {
2823 m_nBufferSize = nSize;
2824 m_pBuffer = new sal_uInt8[m_nBufferSize+1];
2825 }
2826 }
2827 // -----------------------------------------------------------------------------
WriteBuffer()2828 sal_Bool ODbaseTable::WriteBuffer()
2829 {
2830 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::WriteBuffer" );
2831 OSL_ENSURE(m_nFilePos >= 1,"SdbDBFCursor::FileFetchRow: ungueltige Record-Position");
2832
2833 // Auf gewuenschten Record positionieren:
2834 long nPos = m_aHeader.db_kopf + (long)(m_nFilePos-1) * m_aHeader.db_slng;
2835 m_pFileStream->Seek(nPos);
2836 return m_pFileStream->Write((char*) m_pBuffer, m_aHeader.db_slng) > 0;
2837 }
2838 // -----------------------------------------------------------------------------
getCurrentLastPos() const2839 sal_Int32 ODbaseTable::getCurrentLastPos() const
2840 {
2841 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "dbase", "Ocke.Janssen@sun.com", "ODbaseTable::getCurrentLastPos" );
2842 return m_aHeader.db_anz;
2843 }
2844