00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025
00026
00027 #define XAPIAN_DEPRECATED(D) D
00028
00029 #include "database.h"
00030 #include "utils.h"
00031 #include <xapian/dbfactory.h>
00032 #include <xapian/error.h>
00033 #include <xapian/version.h>
00034
00035 #include <fstream>
00036 #include <string>
00037
00038 using namespace std;
00039
00040
00041 #ifdef XAPIAN_HAS_INMEMORY_BACKEND
00042 #include "inmemory/inmemory_database.h"
00043 #endif
00044 #ifdef XAPIAN_HAS_QUARTZ_BACKEND
00045 #include "quartz/quartz_database.h"
00046 #endif
00047 #ifdef XAPIAN_HAS_FLINT_BACKEND
00048 #include "flint/flint_database.h"
00049 #endif
00050
00051 namespace Xapian {
00052
00053 #ifdef XAPIAN_HAS_QUARTZ_BACKEND
00054 Database
00055 Quartz::open(const string &dir) {
00056 DEBUGAPICALL_STATIC(Database, "Quartz::open", dir);
00057 return Database(new QuartzDatabase(dir));
00058 }
00059
00060 WritableDatabase
00061 Quartz::open(const string &dir, int action, int block_size) {
00062 DEBUGAPICALL_STATIC(WritableDatabase, "Quartz::open", dir << ", " <<
00063 action << ", " << block_size);
00064 return WritableDatabase(new QuartzWritableDatabase(dir, action,
00065 block_size));
00066 }
00067 #endif
00068
00069 #ifdef XAPIAN_HAS_FLINT_BACKEND
00070 Database
00071 Flint::open(const string &dir) {
00072 DEBUGAPICALL_STATIC(Database, "Flint::open", dir);
00073 return Database(new FlintDatabase(dir));
00074 }
00075
00076 WritableDatabase
00077 Flint::open(const string &dir, int action, int block_size) {
00078 DEBUGAPICALL_STATIC(WritableDatabase, "Flint::open", dir << ", " <<
00079 action << ", " << block_size);
00080 return WritableDatabase(new FlintWritableDatabase(dir, action, block_size));
00081 }
00082 #endif
00083
00084 #ifdef XAPIAN_HAS_INMEMORY_BACKEND
00085
00086
00087 WritableDatabase
00088 InMemory::open() {
00089 DEBUGAPICALL_STATIC(Database, "InMemory::open", "");
00090 return WritableDatabase(new InMemoryDatabase());
00091 }
00092 #endif
00093
00094 static void
00095 open_stub(Database *db, const string &file)
00096 {
00097
00098
00099 ifstream stub(file.c_str());
00100 string line;
00101 int line_no = 1;
00102 bool ok = false;
00103 while (getline(stub, line)) {
00104 string::size_type space = line.find(' ');
00105 if (space != string::npos) {
00106 string type = line.substr(0, space);
00107 line.erase(0, space + 1);
00108 if (type == "auto") {
00109 db->add_database(Database(line));
00110 ok = true;
00111 #ifdef XAPIAN_HAS_FLINT_BACKEND
00112 } else if (type == "flint") {
00113 db->add_database(Flint::open(line));
00114 ok = true;
00115 #endif
00116 #ifdef XAPIAN_HAS_QUARTZ_BACKEND
00117 } else if (type == "quartz") {
00118 db->add_database(Quartz::open(line));
00119 ok = true;
00120 #endif
00121 #ifdef XAPIAN_HAS_REMOTE_BACKEND
00122 } else if (type == "remote") {
00123 string::size_type colon = line.find(':');
00124 if (colon == 0) {
00125
00126
00127
00128
00129 space = line.find(' ');
00130 string args;
00131 if (space != string::npos) {
00132 args = line.substr(space + 1);
00133 line = line.substr(1, space - 1);
00134 } else {
00135 line.erase(0, 1);
00136 }
00137 db->add_database(Remote::open(line, args));
00138 ok = true;
00139 } else if (colon != string::npos) {
00140
00141
00142 unsigned int port = atoi(line.c_str() + colon + 1);
00143 line.erase(colon);
00144 db->add_database(Remote::open(line, port));
00145 ok = true;
00146 }
00147 #endif
00148 }
00149 }
00150 if (!ok) break;
00151 ++line_no;
00152 }
00153 if (!ok) {
00154
00155
00156
00157
00158
00159 throw DatabaseOpeningError("Bad line " + om_tostring(line_no) + " in stub database file `" + file + "'");
00160 }
00161 }
00162
00163 Database
00164 Auto::open_stub(const string &file)
00165 {
00166 DEBUGAPICALL_STATIC(Database, "Auto::open_stub", file);
00167 Database db;
00168 open_stub(&db, file);
00169 return db;
00170 }
00171
00172 Database::Database(const string &path)
00173 {
00174 DEBUGAPICALL(void, "Database::Database", path);
00175
00176
00177 if (file_exists(path)) {
00178 open_stub(this, path);
00179 return;
00180 }
00181
00182 #ifdef XAPIAN_HAS_FLINT_BACKEND
00183 if (file_exists(path + "/iamflint")) {
00184 internal.push_back(new FlintDatabase(path));
00185 return;
00186 }
00187 #endif
00188 #ifdef XAPIAN_HAS_QUARTZ_BACKEND
00189 if (file_exists(path + "/record_DB")) {
00190 internal.push_back(new QuartzDatabase(path));
00191 return;
00192 }
00193 #endif
00194
00195 throw DatabaseOpeningError("Couldn't detect type of database");
00196 }
00197
00198 WritableDatabase::WritableDatabase(const std::string &path, int action)
00199 : Database()
00200 {
00201 DEBUGAPICALL(void, "WritableDatabase::WritableDatabase",
00202 path << ", " << action);
00203 #if defined XAPIAN_HAS_FLINT_BACKEND && defined XAPIAN_HAS_QUARTZ_BACKEND
00204
00205 if (!file_exists(path + "/record_DB")) {
00206 internal.push_back(new FlintWritableDatabase(path, action, 8192));
00207 } else {
00208 internal.push_back(new QuartzWritableDatabase(path, action, 8192));
00209 }
00210 #elif defined XAPIAN_HAS_FLINT_BACKEND
00211
00212 internal.push_back(new FlintWritableDatabase(path, action, 8192));
00213 #elif defined XAPIAN_HAS_QUARTZ_BACKEND
00214
00215 internal.push_back(new QuartzWritableDatabase(path, action, 8192));
00216 #else
00217 throw FeatureUnavailableError("No disk-based writable backend is enabled");
00218 #endif
00219 }
00220
00222
00223 Database::Internal::Internal()
00224 : transaction_state(TRANSACTION_NONE)
00225 {
00226 }
00227
00228 Database::Internal::~Internal()
00229 {
00230 }
00231
00232 void
00233 Database::Internal::keep_alive()
00234 {
00235
00236 }
00237
00238
00239
00240 void
00241 Database::Internal::dtor_called()
00242 {
00243 try {
00244 if (transaction_active()) {
00245 cancel_transaction();
00246 } else if (transaction_state == TRANSACTION_NONE) {
00247 flush();
00248 }
00249 } catch (...) {
00250
00251
00252 }
00253 }
00254
00255 void
00256 Database::Internal::flush()
00257 {
00258
00259 Assert(false);
00260 }
00261
00262 void
00263 Database::Internal::cancel()
00264 {
00265
00266 Assert(false);
00267 }
00268
00269 void
00270 Database::Internal::begin_transaction(bool flushed)
00271 {
00272 if (transaction_state != TRANSACTION_NONE) {
00273 if (transaction_state == TRANSACTION_UNIMPLEMENTED)
00274 throw Xapian::UnimplementedError("This backend doesn't implement transactions");
00275 throw InvalidOperationError("Cannot begin transaction - transaction already in progress");
00276 }
00277 if (flushed) {
00278
00279
00280 flush();
00281 transaction_state = TRANSACTION_FLUSHED;
00282 } else {
00283 transaction_state = TRANSACTION_UNFLUSHED;
00284 }
00285 }
00286
00287 void
00288 Database::Internal::commit_transaction()
00289 {
00290 if (!transaction_active()) {
00291 if (transaction_state == TRANSACTION_UNIMPLEMENTED)
00292 throw Xapian::UnimplementedError("This backend doesn't implement transactions");
00293 throw InvalidOperationError("Cannot commit transaction - no transaction currently in progress");
00294 }
00295 bool flushed = (transaction_state == TRANSACTION_FLUSHED);
00296 transaction_state = TRANSACTION_NONE;
00297
00298
00299 if (flushed) flush();
00300 }
00301
00302 void
00303 Database::Internal::cancel_transaction()
00304 {
00305 if (!transaction_active()) {
00306 if (transaction_state == TRANSACTION_UNIMPLEMENTED)
00307 throw Xapian::UnimplementedError("This backend doesn't implement transactions");
00308 throw InvalidOperationError("Cannot cancel transaction - no transaction currently in progress");
00309 }
00310 transaction_state = TRANSACTION_NONE;
00311 cancel();
00312 }
00313
00314 Xapian::docid
00315 Database::Internal::add_document(const Xapian::Document &)
00316 {
00317
00318 Assert(false);
00319 return 0;
00320 }
00321
00322 void
00323 Database::Internal::delete_document(Xapian::docid)
00324 {
00325
00326 Assert(false);
00327 }
00328
00329 void
00330 Database::Internal::delete_document(const std::string & unique_term)
00331 {
00332
00333 Xapian::Internal::RefCntPtr<LeafPostList> pl(open_post_list(unique_term));
00334 while (pl->next(), !pl->at_end()) {
00335 delete_document(pl->get_docid());
00336 }
00337 }
00338
00339 void
00340 Database::Internal::replace_document(Xapian::docid, const Xapian::Document &)
00341 {
00342
00343 Assert(false);
00344 }
00345
00346 Xapian::docid
00347 Database::Internal::replace_document(const std::string & unique_term,
00348 const Xapian::Document & document)
00349 {
00350
00351 Xapian::Internal::RefCntPtr<LeafPostList> pl(open_post_list(unique_term));
00352 pl->next();
00353 if (pl->at_end()) {
00354 return add_document(document);
00355 }
00356 Xapian::docid did = pl->get_docid();
00357 replace_document(did, document);
00358 while (pl->next(), !pl->at_end()) {
00359 delete_document(pl->get_docid());
00360 }
00361 return did;
00362 }
00363
00364 TermList *
00365 Database::Internal::open_spelling_termlist(const string &) const
00366 {
00367
00368
00369
00370 return NULL;
00371 }
00372
00373 TermList *
00374 Database::Internal::open_spelling_wordlist() const
00375 {
00376
00377
00378
00379 return NULL;
00380 }
00381
00382 Xapian::doccount
00383 Database::Internal::get_spelling_frequency(const string &) const
00384 {
00385
00386
00387
00388 return 0;
00389 }
00390
00391 void
00392 Database::Internal::add_spelling(const string &, Xapian::termcount) const
00393 {
00394 throw Xapian::UnimplementedError("This backend doesn't implement spelling correction");
00395 }
00396
00397 void
00398 Database::Internal::remove_spelling(const string &, Xapian::termcount) const
00399 {
00400 throw Xapian::UnimplementedError("This backend doesn't implement spelling correction");
00401 }
00402
00403 TermList *
00404 Database::Internal::open_synonym_termlist(const string &) const
00405 {
00406
00407
00408
00409 return NULL;
00410 }
00411
00412 TermList *
00413 Database::Internal::open_synonym_keylist(const string &) const
00414 {
00415
00416
00417
00418 return NULL;
00419 }
00420
00421 void
00422 Database::Internal::add_synonym(const string &, const string &) const
00423 {
00424 throw Xapian::UnimplementedError("This backend doesn't implement synonyms");
00425 }
00426
00427 void
00428 Database::Internal::remove_synonym(const string &, const string &) const
00429 {
00430 throw Xapian::UnimplementedError("This backend doesn't implement synonyms");
00431 }
00432
00433 void
00434 Database::Internal::clear_synonyms(const string &) const
00435 {
00436 throw Xapian::UnimplementedError("This backend doesn't implement synonyms");
00437 }
00438
00439 string
00440 Database::Internal::get_metadata(const string &) const
00441 {
00442 return string();
00443 }
00444
00445 TermList *
00446 Database::Internal::open_metadata_keylist(const std::string &) const
00447 {
00448
00449
00450 return NULL;
00451 }
00452
00453 void
00454 Database::Internal::set_metadata(const string &, const string &)
00455 {
00456 throw Xapian::UnimplementedError("This backend doesn't implement metadata");
00457 }
00458
00459 void
00460 Database::Internal::reopen()
00461 {
00462
00463
00464 }
00465
00466 void
00467 Database::Internal::request_document(Xapian::docid ) const
00468 {
00469 }
00470
00471 Xapian::Document::Internal *
00472 Database::Internal::collect_document(Xapian::docid did) const
00473 {
00474 return open_document(did);
00475 }
00476
00477 RemoteDatabase *
00478 Database::Internal::as_remotedatabase()
00479 {
00480 return NULL;
00481 }
00482
00483 }