You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/lib/catalog/catalog.cpp

463 lines
9.6 KiB

/* This file is part of KDevelop
Copyright (C) 2003 Roberto Raggi <roberto@kdevelop.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "catalog.h"
#include <tqdir.h>
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqdatastream.h>
#include <krandomsequence.h>
#include <kdebug.h>
#include <cstring>
#include <cstdlib>
#include <db.h>
#include <config.h>
struct _Catalog_Private
{
TQString dbName;
DB* dbp;
TQMap<TQCString, DB*> indexList;
KRandomSequence rnd;
bool enabled;
_Catalog_Private()
: dbp( 0 ), enabled( true )
{
}
bool hasIndex( const TQCString& name ) const
{
return indexList.tqcontains( name );
}
DB* index( const TQCString& name )
{
return indexList[ name ];
}
bool addItem( DB* dbp, const TQCString& id, const Tag& tag )
{
Q_ASSERT( dbp != 0 );
DBT key, data;
int ret;
std::memset( &key, 0, sizeof(key) );
std::memset( &data, 0, sizeof(data) );
TQByteArray a1;
{
TQDataStream stream( a1, IO_WriteOnly );
stream << id;
key.data = a1.data();
key.size = a1.size();
}
TQByteArray a2;
{
TQDataStream stream( a2, IO_WriteOnly );
tag.store( stream );
data.data = a2.data();
data.size = a2.size();
}
ret = dbp->put( dbp, 0, &key, &data, 0 );
return ret == 0;
}
bool addItem( DB* dbp, const TQVariant& id, const TQCString& v )
{
Q_ASSERT( dbp != 0 );
DBT key, data;
int ret;
std::memset( &key, 0, sizeof(key) );
std::memset( &data, 0, sizeof(data) );
TQByteArray a1;
{
TQDataStream stream( a1, IO_WriteOnly );
stream << id;
key.data = a1.data();
key.size = a1.size();
}
TQByteArray a2;
{
TQDataStream stream( a2, IO_WriteOnly );
stream << v;
data.data = a2.data();
data.size = a2.size();
}
ret = dbp->put( dbp, 0, &key, &data, 0 );
return ret == 0;
}
};
/*!
\fn Catalog::Catalog
*/
Catalog::Catalog()
: d( new _Catalog_Private() )
{
}
/*!
\fn Catalog::~Catalog
*/
Catalog::~Catalog()
{
close();
delete( d );
d = 0;
}
/*!
\fn Catalog::indexList() const
*/
TQValueList<TQCString> Catalog::indexList() const
{
TQValueList<TQCString> l;
TQMap<TQCString, DB*>::Iterator it = d->indexList.begin();
while( it != d->indexList.end() ){
l << it.key();
++it;
}
return l;
}
bool Catalog::enabled() const
{
return d->enabled;
}
void Catalog::setEnabled( bool isEnabled )
{
d->enabled = isEnabled;
}
/*!
\fn Catalog::addIndex( const TQString& name )
@todo document these functions
*/
void Catalog::addIndex( const TQCString& name )
{
Q_ASSERT( d->dbp != 0 );
TQMap<TQCString, DB*>::Iterator it = d->indexList.tqfind( name );
if( it == d->indexList.end() ){
DB* dbp = 0;
int ret;
if ((ret = db_create(&dbp, 0, 0)) != 0) {
kdDebug() << "db_create: " << db_strerror(ret) << endl;
return /*false*/;
}
if ((ret = dbp->set_flags(dbp, DB_DUP | DB_DUPSORT)) != 0) {
dbp->err(dbp, ret, "set_flags: DB_DUP | DB_DUPSORT");
dbp->close( dbp, 0 );
return;
}
TQFileInfo fileInfo( d->dbName );
TQString indexName = fileInfo.dirPath(true) + "/" + fileInfo.baseName(true) + "." + TQString(name) + ".idx";
if( (ret = dbp->set_cachesize( dbp, 0, 2 * 1024 * 1024, 0 )) != 0 ){
kdDebug() << "set_cachesize: " << db_strerror(ret) << endl;
}
if ((ret = dbp->open(
dbp, NULL, TQFile::encodeName( indexName ).data(), 0, DB_BTREE, DB_CREATE, 0664)) != 0) {
kdDebug() << "db_open: " << db_strerror(ret) << endl;
dbp->close( dbp, 0 );
return;
}
d->indexList[ name ] = dbp;
}
}
/*!
\fn Catalog::close()
*/
void Catalog::close()
{
d->dbName = TQString();
TQMap<TQCString, DB*>::Iterator it = d->indexList.begin();
while( it != d->indexList.end() ){
if( it.data() ){
it.data()->close( it.data(), 0 );
}
++it;
}
d->indexList.clear();
if( d->dbp != 0 ){
d->dbp->close( d->dbp, 0 );
d->dbp = 0;
}
}
/*!
\fn Catalog::open( const TQString& dbName )
*/
void Catalog::open( const TQString& dbName )
{
Q_ASSERT( d->dbp == 0 );
d->dbName = dbName;
int ret;
if ((ret = db_create(&d->dbp, 0, 0)) != 0) {
kdDebug() << "db_create: " << db_strerror(ret) << endl;
return /*false*/;
}
if ((ret = d->dbp->set_flags(d->dbp, DB_RECNUM)) != 0) {
d->dbp->err(d->dbp, ret, "set_flags: DB_RECNUM");
close();
return;
}
if( (ret = d->dbp->set_cachesize( d->dbp, 0, 2 * 1024 * 1024, 0 )) != 0 ){
kdDebug() << "set_cachesize: " << db_strerror(ret) << endl;
}
if ((ret = d->dbp->open(
d->dbp, NULL, d->dbName.local8Bit(), 0, DB_BTREE, DB_CREATE, 0664)) != 0) {
kdDebug() << "db_open: " << db_strerror(ret) << endl;
close();
return;
}
}
/*!
\fn Catalog::dbName() const
*/
TQString Catalog::dbName() const
{
return d->dbName;
}
/*!
\fn Catalog::isValid() const
*/
bool Catalog::isValid() const
{
return d->dbp != 0;
}
/*!
\fn Catalog::addItem( Tag& tag )
*/
void Catalog::addItem( Tag& tag )
{
if( tag.name().isEmpty() )
return;
TQCString id = generateId();
tag.setId( id );
if( d->addItem(d->dbp, id, tag) ){
TQMap<TQCString, DB*>::Iterator it = d->indexList.begin();
while( it != d->indexList.end() ){
if( tag.hasAttribute(it.key()) )
d->addItem( it.data(), tag.attribute(it.key()), id );
++it;
}
}
}
/*!
\fn Catalog::getItemById( const TQString& id )
*/
Tag Catalog::getItemById( const TQCString& id )
{
Q_ASSERT( d->dbp != 0 );
DBT key, data;
std::memset( &key, 0, sizeof(key) );
std::memset( &data, 0, sizeof(data) );
TQByteArray a1;
{
TQDataStream stream( a1, IO_WriteOnly );
stream << id;
key.data = a1.data();
key.size = a1.size();
}
int ret = d->dbp->get( d->dbp, 0, &key, &data, 0 );
Q_ASSERT( ret == 0 );
Tag tag;
if( ret == 0 ){
TQByteArray a;
a.setRawData( (const char*) data.data, data.size );
TQDataStream stream( a, IO_ReadOnly );
tag.load( stream );
a.resetRawData( (const char*) data.data, data.size );
}
return tag;
}
/*!
\fn Catalog::sync()
*/
void Catalog::sync()
{
Q_ASSERT( d->dbp != 0 );
d->dbp->sync( d->dbp, 0 );
TQMap<TQCString, DB*>::Iterator it = d->indexList.begin();
while( it != d->indexList.end() ){
it.data()->sync( it.data(), 0 );
++it;
}
}
/*!
\fn Catalog::query( const TQValueList<QueryArgument>& args )
*/
TQValueList<Tag> Catalog::query( const TQValueList<QueryArgument>& args )
{
TQValueList<Tag> tags;
DBT key, data;
DBC** cursors = new DBC* [ args.size() + 1 ];
TQValueList< TQPair<TQCString,TQVariant> >::ConstIterator it = args.begin();
int current = 0;
while( it != args.end() ){
TQCString indexName = (*it).first;
TQVariant value = (*it).second;
if( d->hasIndex(indexName) ) {
DB* dbp = d->index( indexName );
Q_ASSERT( dbp != 0 );
std::memset( &key, 0, sizeof(key) );
std::memset( &data, 0, sizeof(data) );
TQByteArray a1;
{
TQDataStream stream( a1, IO_WriteOnly );
stream << value;
key.data = a1.data();
key.size = a1.size();
}
DBC* cursor = 0;
int rtn = dbp->cursor( dbp, 0, &cursor, 0 );
if ( rtn == 0 ) {
rtn = cursor->c_get( cursor, &key, &data, DB_SET );
if ( rtn == 0 ) {
cursors[ current++ ] = cursor;
}
else if ( rtn != DB_NOTFOUND) {
kdDebug() << "fetching cursor failed: " << db_strerror(rtn) << endl;
cursor->c_close(cursor);
}
}
else {
kdDebug() << "creating cursor failed: " << db_strerror(rtn) << endl;
}
}
++it;
}
cursors[ current ] = 0;
if( current == args.size() ) {
DBC* join_curs = 0;
int rtn = d->dbp->join( d->dbp, cursors, &join_curs, 0 );
if ( rtn == 0 ) {
std::memset( &key, 0, sizeof(key) );
std::memset( &data, 0, sizeof(data) );
while( join_curs->c_get(join_curs, &key, &data, 0) == 0 ) {
TQByteArray a2;
a2.setRawData( (const char*) data.data, data.size );
TQDataStream s( a2, IO_ReadOnly );
Tag tag;
tag.load( s );
a2.resetRawData( (const char*) data.data, data.size );
tags << tag;
}
join_curs->c_close( join_curs );
}
else {
kdDebug() << "joining results failed: " << db_strerror(rtn) << endl;
}
}
DBC** c = cursors;
while( *c != 0 ){
(*c)->c_close( *c );
++c;
}
delete[] cursors;
return tags;
}
TQCString Catalog::generateId()
{
static int n = 1;
TQCString asStr;
asStr.sprintf( "%05d", n++ );
return asStr;
}