update dev300-m58
[ooovba.git] / xmlhelp / source / cxxhelp / provider / db.cxx
blob989bed4a96740694c727597e51b296201a82fcdf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: db.cxx,v $
10 * $Revision: 1.8 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmlhelp.hxx"
34 #include "db.hxx"
36 #include <rtl/alloc.h>
37 #include <cstring>
39 #include "com/sun/star/io/XSeekable.hpp"
41 #ifdef TEST_DBHELP
42 #include <osl/time.h>
43 #endif
45 using namespace com::sun::star;
46 using namespace com::sun::star::uno;
47 using namespace com::sun::star::io;
49 namespace berkeleydbproxy {
51 //----------------------------------------------------------------------------
52 namespace db_internal
54 // static void raise_error(int dberr, const char * where);
56 static inline int check_error(int dberr, const char * where)
58 (void)where;
60 // if (dberr) raise_error(dberr,where);
61 return dberr;
65 void DBData::copyToBuffer( const char* pSrcData, int nSize )
67 m_nSize = nSize;
68 delete [] m_pBuffer;
69 m_pBuffer = new char[m_nSize+1];
70 memcpy( m_pBuffer, pSrcData, m_nSize );
71 m_pBuffer[m_nSize] = 0;
75 // DBHelp
77 bool DBHelp::implReadLenAndData( const char* pData, int& riPos, DBData& rValue )
79 bool bSuccess = false;
81 // Read key len
82 const char* pStartPtr = pData + riPos;
83 char* pEndPtr;
84 sal_Int32 nKeyLen = strtol( pStartPtr, &pEndPtr, 16 );
85 if( pEndPtr == pStartPtr )
86 return bSuccess;
87 riPos += (pEndPtr - pStartPtr) + 1;
89 const char* pKeySrc = pData + riPos;
90 rValue.copyToBuffer( pKeySrc, nKeyLen );
91 riPos += nKeyLen + 1;
93 bSuccess = true;
94 return bSuccess;
97 #ifdef TEST_DBHELP
99 typedef std::pair< rtl::OString, rtl::OString > KeyValPair;
100 typedef std::vector< KeyValPair > KeyValPairVector;
102 void testWriteKeyValue( FILE* pFile, const KeyValPair& rKeyValPair )
104 if( pFile == NULL )
105 return;
106 char cLF = 10;
108 const rtl::OString& aKeyStr = rKeyValPair.first;
109 const rtl::OString& aValueStr = rKeyValPair.second;
110 int nKeyLen = aKeyStr.getLength();
111 int nValueLen = aValueStr.getLength();
112 fprintf( pFile, "%x ", nKeyLen );
113 if( nKeyLen > 0 )
114 fwrite( aKeyStr.getStr(), 1, nKeyLen, pFile );
115 fprintf( pFile, " %x ", nValueLen );
116 if( nValueLen > 0 )
117 fwrite( aValueStr.getStr(), 1, nValueLen, pFile );
118 fprintf( pFile, "%c", cLF );
121 bool DBHelp::testAgainstDb( const rtl::OString& fileName, bool bOldDbAccess )
123 bool bSuccess = true;
125 KeyValPairVector avKeyValPair;
127 rtl::OString aOutFileName = fileName;
128 aOutFileName += "_TestOut";
129 if( bOldDbAccess )
130 aOutFileName += "_Old";
131 FILE* pFile = fopen( aOutFileName.getStr(), "wb" );
133 // Get all values
134 Db table;
135 if( 0 == table.open( 0,fileName.getStr(),0,DB_BTREE,DB_RDONLY,0644 ) )
137 bool first = true;
139 Dbc* cursor = 0;
140 table.cursor( 0,&cursor,0 );
141 Dbt key_,data;
142 key_.set_flags( DB_DBT_MALLOC ); // Initially the cursor must allocate the necessary memory
143 data.set_flags( DB_DBT_MALLOC );
145 while( cursor && DB_NOTFOUND != cursor->get( &key_,&data,DB_NEXT ) )
147 rtl::OString keyword( static_cast<sal_Char*>(key_.get_data()),
148 key_.get_size() );
149 rtl::OString value( static_cast<sal_Char*>(data.get_data()),
150 data.get_size() );
152 KeyValPair aPair( keyword, value );
153 avKeyValPair.push_back( aPair );
154 if( pFile != NULL )
155 testWriteKeyValue( pFile, aPair );
157 if( first )
159 key_.set_flags( DB_DBT_REALLOC );
160 data.set_flags( DB_DBT_REALLOC );
161 first = false;
165 if( cursor ) cursor->close();
167 table.close( 0 );
169 // TEST
170 DBData aDBData;
171 Db tableTest;
172 Dbt data;
174 int nOkCount = 0;
175 int nErrCount = 0;
177 bool bTestSuccess;
178 const char* pTestReadData = NULL;
179 int nTestReadDataSize = 0;
181 sal_uInt32 starttime = osl_getGlobalTimer();
182 sal_uInt32 afterfirsttime = starttime;
184 if( pFile != NULL )
186 if( bOldDbAccess )
187 fprintf( pFile, "\nTesting old access:\n" );
188 else
189 fprintf( pFile, "\nTesting new access:\n" );
192 KeyValPairVector::const_iterator it;
193 bool bFirst = true;
194 for( it = avKeyValPair.begin() ; it != avKeyValPair.end() ; ++it )
196 const KeyValPair& rKeyValPair = *it;
198 const rtl::OString& aKeyStr = rKeyValPair.first;
199 const rtl::OString& aValueStr = rKeyValPair.second;
200 int nKeyLen = aKeyStr.getLength();
201 int nValueLen = aValueStr.getLength();
203 const sal_Char* ptr = aValueStr.getStr();
205 bTestSuccess = false;
206 pTestReadData = NULL;
207 nTestReadDataSize = 0;
208 if( bOldDbAccess )
210 if( bFirst )
212 if( tableTest.open( 0,fileName.getStr(),0,DB_BTREE,DB_RDONLY,0644 ) )
214 if( pFile != NULL )
215 fprintf( pFile, "Cannot open database\n" );
217 break;
221 Dbt key( static_cast< void* >( const_cast< sal_Char* >( aKeyStr.getStr() ) ), aKeyStr.getLength() );
222 int err = tableTest.get( 0, &key, &data, 0 );
223 if( err == 0 )
225 bTestSuccess = true;
226 pTestReadData = static_cast< sal_Char* >( data.get_data() );
227 nTestReadDataSize = data.get_size();
230 else
232 bTestSuccess = getValueForKey( aKeyStr, aDBData );
233 if( bTestSuccess )
235 pTestReadData = aDBData.getData();
236 nTestReadDataSize = aDBData.getSize();
239 if( bFirst )
241 afterfirsttime = osl_getGlobalTimer();
242 bFirst = false;
244 int nError = 0;
245 if( bTestSuccess && pTestReadData != NULL )
247 int nCmp = memcmp( ptr, pTestReadData, nValueLen );
248 if( nCmp == 0 )
249 ++nOkCount;
250 else
251 nError = 1;
253 if( nValueLen != nTestReadDataSize )
254 nError = 2;
256 else
257 nError = 3;
259 if( nError != 0 )
261 bSuccess = false;
262 ++nErrCount;
264 if( pFile != NULL )
266 fprintf( pFile, "ERROR, not found:\n" );
267 testWriteKeyValue( pFile, rKeyValPair );
268 fprintf( pFile, "\nError Code: %d\n", nError );
272 tableTest.close( 0 );
274 sal_uInt32 endtime = osl_getGlobalTimer();
275 double dDiffTime = (endtime-starttime) / 1000.0;
276 double dDiffFirstTime = (afterfirsttime-starttime) / 1000.0;
277 if( pFile != NULL )
279 int nCount = avKeyValPair.size();
280 fprintf( pFile, "%d key/values in total, read %d correctly, %d errors\n",
281 nCount, nOkCount, nErrCount );
282 fprintf( pFile, "Time taken: %g s (First access %g s)\n", dDiffTime, dDiffFirstTime );
283 fprintf( pFile, "Average time per access: %g s\n", dDiffTime / nCount );
286 if( pFile != NULL )
287 fclose( pFile );
289 return bSuccess;
292 #endif
295 void DBHelp::createHashMap( bool bOptimizeForPerformance )
297 releaseHashMap();
298 if( bOptimizeForPerformance )
300 if( m_pStringToDataMap != NULL )
301 return;
302 m_pStringToDataMap = new StringToDataMap();
304 else
306 if( m_pStringToValPosMap != NULL )
307 return;
308 m_pStringToValPosMap = new StringToValPosMap();
311 Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileName );
312 if( xIn.is() )
314 Sequence< sal_Int8 > aData;
315 sal_Int32 nSize = m_xSFA->getSize( m_aFileName );
316 sal_Int32 nRead = xIn->readBytes( aData, nSize );
318 const char* pData = (const char*)aData.getConstArray();
319 int iPos = 0;
320 while( iPos < nRead )
322 DBData aDBKey;
323 if( !implReadLenAndData( pData, iPos, aDBKey ) )
324 break;
326 rtl::OString aOKeyStr = aDBKey.getData();
328 // Read val len
329 const char* pStartPtr = pData + iPos;
330 char* pEndPtr;
331 sal_Int32 nValLen = strtol( pStartPtr, &pEndPtr, 16 );
332 if( pEndPtr == pStartPtr )
333 break;
335 iPos += (pEndPtr - pStartPtr) + 1;
337 if( bOptimizeForPerformance )
339 const char* pValSrc = pData + iPos;
340 rtl::OString aValStr( pValSrc, nValLen );
341 (*m_pStringToDataMap)[aOKeyStr] = aValStr;
343 else
345 // store value start position
346 (*m_pStringToValPosMap)[aOKeyStr] = std::pair<int,int>( iPos, nValLen );
348 iPos += nValLen + 1;
351 xIn->closeInput();
355 void DBHelp::releaseHashMap( void )
357 if( m_pStringToDataMap != NULL )
359 delete m_pStringToDataMap;
360 m_pStringToDataMap = NULL;
362 if( m_pStringToValPosMap != NULL )
364 delete m_pStringToValPosMap;
365 m_pStringToValPosMap = NULL;
370 bool DBHelp::getValueForKey( const rtl::OString& rKey, DBData& rValue )
372 bool bSuccess = false;
373 if( !m_xSFA.is() )
374 return bSuccess;
379 if( m_pStringToDataMap == NULL && m_pStringToValPosMap == NULL )
381 bool bOptimizeForPerformance = false;
382 createHashMap( bOptimizeForPerformance );
385 if( m_pStringToValPosMap != NULL )
387 StringToValPosMap::const_iterator it = m_pStringToValPosMap->find( rKey );
388 if( it != m_pStringToValPosMap->end() )
390 const std::pair<int,int>& rValPair = it->second;
391 int iValuePos = rValPair.first;
392 int nValueLen = rValPair.second;
394 Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileName );
395 if( xIn.is() )
397 Reference< XSeekable > xXSeekable( xIn, UNO_QUERY );
398 if( xXSeekable.is() )
400 xXSeekable->seek( iValuePos );
402 Sequence< sal_Int8 > aData;
403 sal_Int32 nRead = xIn->readBytes( aData, nValueLen );
404 if( nRead == nValueLen )
406 const char* pData = (const sal_Char*)aData.getConstArray();
407 rValue.copyToBuffer( pData, nValueLen );
408 bSuccess = true;
411 xIn->closeInput();
416 else if( m_pStringToDataMap != NULL )
418 StringToDataMap::const_iterator it = m_pStringToDataMap->find( rKey );
419 if( it != m_pStringToDataMap->end() )
421 const rtl::OString& rValueStr = it->second;
422 int nValueLen = rValueStr.getLength();
423 const char* pData = rValueStr.getStr();
424 rValue.copyToBuffer( pData, nValueLen );
425 bSuccess = true;
430 catch( Exception & )
432 bSuccess = false;
435 return bSuccess;
438 bool DBHelp::startIteration( void )
440 bool bSuccess = false;
442 sal_Int32 nSize = m_xSFA->getSize( m_aFileName );
444 Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileName );
445 if( xIn.is() )
447 m_nItRead = xIn->readBytes( m_aItData, nSize );
448 if( m_nItRead == nSize )
450 bSuccess = true;
451 m_pItData = (const char*)m_aItData.getConstArray();
452 m_iItPos = 0;
454 else
456 stopIteration();
460 return bSuccess;
463 bool DBHelp::getNextKeyAndValue( DBData& rKey, DBData& rValue )
465 bool bSuccess = false;
467 if( m_iItPos < m_nItRead )
469 if( implReadLenAndData( m_pItData, m_iItPos, rKey ) )
471 if( implReadLenAndData( m_pItData, m_iItPos, rValue ) )
472 bSuccess = true;
476 return bSuccess;
479 void DBHelp::stopIteration( void )
481 m_aItData = Sequence<sal_Int8>();
482 m_pItData = NULL;
483 m_nItRead = -1;
484 m_iItPos = -1;
488 Db::Db()
490 db_internal::check_error( db_create(&m_pDBP,0,0),"Db::Db" );
491 m_pDBHelp = NULL;
495 Db::~Db()
497 if (m_pDBP)
499 // should not happen
500 // TODO: add assert
503 delete m_pDBHelp;
507 int Db::close(u_int32_t flags)
509 int error = m_pDBP->close(m_pDBP,flags);
510 m_pDBP = 0;
511 return db_internal::check_error(error,"Db::close");
514 int Db::open(DB_TXN *txnid,
515 const char *file,
516 const char *database,
517 DBTYPE type,
518 u_int32_t flags,
519 int mode)
521 int err = m_pDBP->open(m_pDBP,txnid,file,database,type,flags,mode);
522 return db_internal::check_error( err,"Db::open" );
526 int Db::get(DB_TXN *txnid, Dbt *key, Dbt *data, u_int32_t flags)
528 int err = m_pDBP->get(m_pDBP,txnid,key,data,flags);
530 // these are non-exceptional outcomes
531 if (err != DB_NOTFOUND && err != DB_KEYEMPTY)
532 db_internal::check_error( err,"Db::get" );
534 return err;
537 int Db::cursor(DB_TXN *txnid, Dbc **cursorp, u_int32_t flags)
539 DBC * dbc = 0;
540 int error = m_pDBP->cursor(m_pDBP,txnid,&dbc,flags);
542 if (!db_internal::check_error(error,"Db::cursor"))
543 *cursorp = new Dbc(dbc);
545 return error;
548 //----------------------------------------------------------------------------
550 Dbc::Dbc(DBC * dbc)
551 : m_pDBC(dbc)
555 Dbc::~Dbc()
559 int Dbc::close()
561 int err = m_pDBC->c_close(m_pDBC);
562 delete this;
563 return db_internal::check_error( err,"Dbcursor::close" );
566 int Dbc::get(Dbt *key, Dbt *data, u_int32_t flags)
568 int err = m_pDBC->c_get(m_pDBC,key,data,flags);
570 // these are non-exceptional outcomes
571 if (err != DB_NOTFOUND && err != DB_KEYEMPTY)
572 db_internal::check_error( err, "Dbcursor::get" );
574 return err;
577 //----------------------------------------------------------------------------
580 Dbt::Dbt()
582 using namespace std;
583 DBT * thispod = this;
584 memset(thispod, 0, sizeof *thispod);
588 Dbt::Dbt(void *data_arg, u_int32_t size_arg)
590 using namespace std;
591 DBT * thispod = this;
592 memset(thispod, 0, sizeof *thispod);
593 this->set_data(data_arg);
594 this->set_size(size_arg);
598 Dbt::Dbt(const Dbt & other)
600 using namespace std;
601 const DBT *otherpod = &other;
602 DBT *thispod = this;
603 memcpy(thispod, otherpod, sizeof *thispod);
606 Dbt& Dbt::operator = (const Dbt & other)
608 if (this != &other)
610 using namespace std;
611 const DBT *otherpod = &other;
612 DBT *thispod = this;
613 memcpy(thispod, otherpod, sizeof *thispod);
615 return *this;
619 Dbt::~Dbt()
623 void * Dbt::get_data() const
625 return this->data;
628 void Dbt::set_data(void *value)
630 this->data = value;
633 u_int32_t Dbt::get_size() const
635 return this->size;
638 void Dbt::set_size(u_int32_t value)
640 this->size = value;
643 void Dbt::set_flags(u_int32_t value)
645 this->flags = value;
648 //----------------------------------------------------------------------------
650 void db_internal::raise_error(int dberr, const char * where)
652 if (!where) where = "<unknown>";
654 const char * dberrmsg = db_strerror(dberr);
655 if (!dberrmsg || !*dberrmsg) dberrmsg = "<unknown DB error>";
657 rtl::OString msg = where;
658 msg += ": ";
659 msg += dberrmsg;
661 throw DbException(msg);
665 //----------------------------------------------------------------------------
666 } // namespace ecomp