00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __CURSOR_H__
00012 #define __CURSOR_H__
00013
00014 #include "btree.h"
00015 #include "rtree.h"
00016
00017 BEGIN_GIGABASE_NAMESPACE
00018
00019 #include "selection.h"
00020
00021 enum dbCursorType {
00022 dbCursorViewOnly,
00023 dbCursorForUpdate,
00027 dbCursorIncremental,
00036 dbCursorDetached
00037 };
00038
00042 class dbTableIterator : public dbAbstractIterator {
00043 dbAnyCursor* cursor;
00044 dbExprNode* filter;
00045 oid_t curr;
00046
00047 public:
00048 void init(dbAnyCursor* cursor, dbExprNode* filter) {
00049 this->cursor = cursor;
00050 this->filter = filter;
00051 curr = 0;
00052 }
00053
00054 virtual oid_t next();
00055 virtual oid_t prev();
00056 virtual oid_t first();
00057 virtual oid_t last();
00058 };
00059
00060
00061
00065 class GIGABASE_DLL_ENTRY dbAnyCursor : public dbL2List {
00066 friend class dbDatabase;
00067 friend class dbHashTable;
00068 friend class dbRtreePage;
00069 friend class dbBtreePage;
00070 friend class dbRtreeIterator;
00071 friend class dbBtreeIterator;
00072 friend class dbTableIterator;
00073 friend class dbThickBtreePage;
00074 friend class dbSubSql;
00075 friend class dbStatement;
00076 friend class dbServer;
00077 friend class dbAnyContainer;
00078 friend class dbCLI;
00079 friend class JniResultSet;
00080 public:
00085 int getNumberOfRecords() const { return (int)selection.nRows; }
00086
00090 void remove();
00091
00096 bool isEmpty() const {
00097 return currId == 0;
00098 }
00099
00100
00105 oid_t getOid() {
00106 return currId;
00107 }
00108
00113 bool isUpdateCursor() const {
00114 return type == dbCursorForUpdate;
00115 }
00116
00121 bool isLimitReached() const {
00122 return selection.nRows >= limit || selection.nRows >= stmtLimitLen;
00123 }
00124
00135 int select(dbQuery& query, dbCursorType aType, void* paramStruct = NULL);
00136
00144 oid_t* toArrayOfOid(oid_t* arr) const;
00145
00152 int select(dbQuery& query, void* paramStruct = NULL) {
00153 return select(query, defaultType, paramStruct);
00154 }
00155
00163 int select(char_t const* condition, dbCursorType aType, void* paramStruct = NULL) {
00164 dbQuery query(condition);
00165 return select(query, aType, paramStruct);
00166 }
00167
00174 int select(char_t const* condition, void* paramStruct = NULL) {
00175 return select(condition, defaultType, paramStruct);
00176 }
00177
00183 int select(dbCursorType aType) {
00184 type = aType;
00185 reset();
00186 db->select(this);
00187 if (gotoFirst() && prefetch) {
00188 fetch();
00189 }
00190 return (int)selection.nRows;
00191 }
00192
00197 int select() {
00198 return select(defaultType);
00199 }
00200
00207 int selectByKey(char_t const* key, void const* value);
00208
00215 int selectByKey(dbFieldDescriptor* field, void const* value);
00216
00225 int selectByKeyRange(char_t const* key, void const* minValue, void const* maxValue, bool ascent = true);
00226
00235 int selectByKeyRange(dbFieldDescriptor* field, void const* minValue, void const* maxValue, bool ascent = true);
00236
00242 bool update() {
00243 if (type != dbCursorForUpdate) {
00244 db->handleError(dbDatabase::CursorError, "Readonly cursor");
00245 }
00246 if (currId == 0) {
00247 db->handleError(dbDatabase::CursorError, "No current record");
00248 }
00249 return db->update(currId, table, record);
00250 }
00251
00255 void removeAll() {
00256 assert(db != NULL);
00257 reset();
00258 db->deleteTable(table);
00259 }
00260
00264 void removeAllSelected();
00265
00269 void setSelectionLimit(size_t lim) { limit = lim; }
00270
00274 void unsetSelectionLimit() { limit = dbDefaultSelectionLimit; }
00275
00282 void setPrefetchMode(bool mode) { prefetch = mode; }
00283
00294 bool isIncremental() {
00295 return iterator != NULL;
00296 }
00297
00302 bool hasIncrementalHint() {
00303 return type == dbCursorIncremental;
00304 }
00305
00310 void enableCheckForDuplicates(bool enabled) {
00311 checkForDuplicatedIsEnabled = enabled;
00312 }
00313
00317 void reset();
00318
00323 bool isLast() const;
00324
00329 bool isFirst() const;
00330
00336 void freeze();
00337
00341 void unfreeze();
00342
00350 bool skip(int n);
00351
00357 int seek(oid_t oid);
00358
00363 dbTableDescriptor* getTable() { return table; }
00364
00365
00370 bool isInSelection(oid_t oid);
00371
00376 void fetch() {
00377 dbRecord* row = (type == dbCursorDetached) ? db->fetchRow(tie, currId) : db->getRow(tie, currId);
00378 table->columns->fetchRecordFields(record, (byte*)row);
00379 }
00380
00384 bool hasNext() const;
00385
00389 bool hasCurrent() const {
00390 return currId != 0;
00391 }
00392
00393 protected:
00394 dbDatabase* db;
00395 dbTableDescriptor* table;
00396 dbCursorType type;
00397 dbCursorType defaultType;
00398 dbSelection selection;
00399 bool allRecords;
00400 oid_t firstId;
00401 oid_t lastId;
00402 oid_t currId;
00403 byte* record;
00404 size_t limit;
00405 dbGetTie tie;
00406 void* paramBase;
00407
00408 bool eliminateDuplicates;
00409 bool checkForDuplicatedIsEnabled;
00410 bool prefetch;
00411 bool removed;
00412 bool lastRecordWasDeleted;
00413
00414 size_t stmtLimitStart;
00415 size_t stmtLimitLen;
00416 size_t nSkipped;
00417
00418 dbAbstractIterator*iterator;
00419 dbBtreeIterator btreeIterator;
00420 dbRtreeIterator rtreeIterator;
00421 dbTableIterator tableIterator;
00422
00423 void checkForDuplicates() {
00424 if (!eliminateDuplicates && checkForDuplicatedIsEnabled && limit > 1) {
00425 eliminateDuplicates = true;
00426 selection.allocateBitmap(db);
00427 }
00428 }
00429
00430 bool isMarked(oid_t oid) {
00431 return selection.bitmap != NULL && (selection.bitmap[(size_t)(oid >> 5)] & (1 << ((int)oid & 31))) != 0;
00432 }
00433
00434 void deallocateBitmap() {
00435 selection.deallocateBitmap();
00436 }
00437
00438 void mark(oid_t oid) {
00439 if (selection.bitmap != NULL) {
00440 selection.bitmap[(size_t)(oid >> 5)] |= 1 << ((int)oid & 31);
00441 }
00442 }
00443
00444 void setStatementLimit(dbQuery const& q) {
00445 stmtLimitStart = q.stmtLimitStartPtr != NULL ? (nat4)*q.stmtLimitStartPtr : q.stmtLimitStart;
00446 stmtLimitLen = q.stmtLimitLenPtr != NULL ? (nat4)*q.stmtLimitLenPtr : q.stmtLimitLen;
00447 }
00448
00449 void truncateSelection() {
00450 selection.truncate(stmtLimitStart, stmtLimitLen);
00451 }
00452
00453 bool add(oid_t oid) {
00454 if (selection.nRows < limit && selection.nRows < stmtLimitLen) {
00455 if (nSkipped < stmtLimitStart) {
00456 nSkipped += 1;
00457 return true;
00458 }
00459 if (eliminateDuplicates) {
00460 if (selection.bitmap[(size_t)(oid >> 5)] & (1 << ((int)oid & 31))) {
00461 return true;
00462 }
00463 selection.bitmap[oid >> 5] |= 1 << (oid & 31);
00464 }
00465 selection.add(oid);
00466 return selection.nRows < limit;
00467 }
00468 return false;
00469 }
00470
00471 byte* fetchNext();
00472 byte* fetchPrev();
00473 byte* fetchFirst();
00474 byte* fetchLast();
00475
00476 bool gotoNext();
00477 bool gotoPrev();
00478 bool gotoFirst();
00479 bool gotoLast();
00480
00481 bool moveNext();
00482 bool movePrev();
00483
00484 void setCurrent(dbAnyReference const& ref);
00485
00486 void setTable(dbTableDescriptor* aTable) {
00487 table = aTable;
00488 db = aTable->db;
00489 }
00490
00491 void setRecord(void* rec) {
00492 record = (byte*)rec;
00493 }
00494
00495 dbAnyCursor(dbTableDescriptor& aTable, dbCursorType aType, byte* rec);
00496
00497 public:
00498 dbAnyCursor(dbCursorType aType = dbCursorViewOnly);
00499 ~dbAnyCursor();
00500 };
00501
00505 template<class T>
00506 class dbCursor : public dbAnyCursor {
00507 private:
00508
00509 dbCursor<T> operator = (dbCursor<T> const& src) {
00510 return *this;
00511 }
00512
00513 protected:
00514 T record;
00515
00516 public:
00521 dbCursor(dbCursorType type = dbCursorViewOnly)
00522 : dbAnyCursor(T::dbDescriptor, type, (byte*)&record) {}
00523
00530 dbCursor(dbDatabase* aDb, dbCursorType type = dbCursorViewOnly)
00531 : dbAnyCursor(T::dbDescriptor, type, (byte*)&record)
00532 {
00533 db = aDb;
00534 dbTableDescriptor* theTable = db->lookupTable(table);
00535 if (theTable != NULL) {
00536 table = theTable;
00537 }
00538 }
00539
00544 T* get() {
00545 return currId == 0 ? (T*)NULL : &record;
00546 }
00547
00552 T* next() {
00553 return (T*)fetchNext();
00554 }
00555
00560 T* prev() {
00561 return (T*)fetchPrev();
00562 }
00563
00568 T* first() {
00569 return (T*)fetchFirst();
00570 }
00571
00576 T* last() {
00577 return (T*)fetchLast();
00578 }
00579
00585 int seek(dbReference<T> const& ref) {
00586 return dbAnyCursor::seek(ref.getOid());
00587 }
00588
00593 T* operator ->() {
00594 if (currId == 0) {
00595 db->handleError(dbDatabase::CursorError, "No current record");
00596 }
00597 return &record;
00598 }
00599
00605 T* at(dbReference<T> const& ref) {
00606 setCurrent(ref);
00607 return &record;
00608 }
00609
00614 dbReference<T> currentId() const {
00615 return dbReference<T>(currId);
00616 }
00617
00622 void toArray(dbArray< dbReference<T> >& arr) const {
00623 arr.resize(selection.nRows);
00624 toArrayOfOid((oid_t*)arr.base());
00625 }
00626
00627 T* prevAvailable() {
00628 if (!removed) {
00629 return prev();
00630 } else {
00631 removed = false;
00632 return lastRecordWasDeleted ? get() : prev();
00633 }
00634 }
00635
00640 bool isInSelection(dbReference<T>& ref) {
00641 return dbAnyCursor::isInSelection(ref.getOid());
00642 }
00643 };
00644
00645 class dbParallelQueryContext {
00646 public:
00647 dbDatabase* const db;
00648 dbCompiledQuery* const query;
00649 dbAnyCursor* cursor;
00650 oid_t firstRow;
00651 dbTableDescriptor* table;
00652 dbSelection selection[dbMaxParallelSearchThreads];
00653
00654 void search(int i);
00655
00656 dbParallelQueryContext(dbDatabase* aDb, dbTableDescriptor* desc,
00657 dbCompiledQuery* aQuery, dbAnyCursor* aCursor)
00658 : db(aDb), query(aQuery), cursor(aCursor), firstRow(desc->firstRow), table(desc) {}
00659 };
00660
00661 END_GIGABASE_NAMESPACE
00662
00663 #endif