00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __CURSOR_H__
00012 #define __CURSOR_H__
00013
00014 BEGIN_FASTDB_NAMESPACE
00015
00016 class dbOrderByNode;
00017
00018 class FASTDB_DLL_ENTRY dbSelection {
00019 public:
00020 enum { quantum = 1024 };
00021 class segment {
00022 public:
00023 segment* prev;
00024 segment* next;
00025 size_t nRows;
00026 oid_t rows[quantum];
00027
00028 segment(segment* after) {
00029 prev = after;
00030 next = NULL;
00031 nRows = 0;
00032 }
00033 };
00034 segment* first;
00035 segment* last;
00036 segment* curr;
00037 size_t nRows;
00038 size_t pos;
00039
00040 segment* createNewSegment(segment* after);
00041
00042 void add(oid_t oid) {
00043 if (last == NULL) {
00044 first = last = createNewSegment(NULL);
00045 } else if (last->nRows == quantum) {
00046 last = last->next = createNewSegment(last);
00047 }
00048 last->rows[last->nRows++] = oid;
00049 nRows += 1;
00050 }
00051
00052 void sort(dbDatabase* db, dbOrderByNode* order);
00053 static int compare(oid_t a, oid_t b, dbOrderByNode* order);
00054
00055 void toArray(oid_t* oids) const;
00056 void truncate(size_t from, size_t length);
00057
00058 dbSelection() {
00059 nRows = 0;
00060 pos = 0;
00061 first = curr = last = NULL;
00062 }
00063 void reverse();
00064 void reset();
00065 };
00066
00067 enum dbCursorType {
00068 dbCursorViewOnly,
00069 dbCursorForUpdate
00070 };
00071
00075 class FASTDB_DLL_ENTRY dbAnyCursor : public dbL2List {
00076 friend class dbAnyContainer;
00077 friend class dbDatabase;
00078 friend class dbHashTable;
00079 friend class dbTtreeNode;
00080 friend class dbRtreePage;
00081 friend class dbSubSql;
00082 friend class dbStatement;
00083 friend class dbServer;
00084 friend class dbCLI;
00085 friend class JniResultSet;
00086 public:
00091 int getNumberOfRecords() const { return (int)selection.nRows; }
00092
00096 void remove();
00097
00102 bool isEmpty() const { return currId == 0; }
00103
00108 bool isUpdateCursor() const {
00109 return type == dbCursorForUpdate;
00110 }
00111
00116 bool isLimitReached() const { return selection.nRows >= limit || selection.nRows >= stmtLimitLen; }
00117
00125 oid_t* toArrayOfOid(oid_t* arr) const;
00126
00137 int select(dbQuery& query, dbCursorType aType, void* paramStruct = NULL) {
00138 type = aType;
00139 reset();
00140 paramBase = paramStruct;
00141 db->select(this, query);
00142 paramBase = NULL;
00143 if (gotoFirst() && prefetch) {
00144 fetch();
00145 }
00146 return (int)selection.nRows;
00147 }
00148
00155 int select(dbQuery& query, void* paramStruct = NULL) {
00156 return select(query, defaultType, paramStruct);
00157 }
00158
00166 int select(char const* condition, dbCursorType aType, void* paramStruct = NULL) {
00167 dbQuery query(condition);
00168 return select(query, aType, paramStruct);
00169 }
00170
00177 int select(char const* condition, void* paramStruct = NULL) {
00178 return select(condition, defaultType, paramStruct);
00179 }
00180
00186 int select(dbCursorType aType) {
00187 type = aType;
00188 reset();
00189 db->select(this);
00190 if (gotoFirst() && prefetch) {
00191 fetch();
00192 }
00193 return (int)selection.nRows;
00194 }
00195
00200 int select() {
00201 return select(defaultType);
00202 }
00203
00210 int selectByKey(char const* key, void const* value);
00211
00219 int selectByKeyRange(char const* key, void const* minValue, void const* maxValue);
00220
00225 void update() {
00226 assert(type == dbCursorForUpdate && currId != 0);
00227 db->update(currId, table, record);
00228 }
00229
00233 void removeAll() {
00234 assert(db != NULL);
00235 db->deleteTable(table);
00236 reset();
00237 }
00238
00242 void removeAllSelected();
00243
00247 void setSelectionLimit(size_t lim) { limit = lim; }
00248
00252 void unsetSelectionLimit() { limit = dbDefaultSelectionLimit; }
00253
00260 void setPrefetchMode(bool mode) { prefetch = mode; }
00261
00265 void reset();
00266
00271 bool isLast() const;
00272
00277 bool isFirst() const;
00278
00284 void freeze();
00285
00289 void unfreeze();
00290
00298 bool skip(int n);
00299
00300
00306 int seek(oid_t oid);
00307
00311 dbTableDescriptor* getTable() { return table; }
00312
00313
00318 void setTable(dbTableDescriptor* aTable) {
00319 table = aTable;
00320 db = aTable->db;
00321 }
00322
00327 void setRecord(void* rec) {
00328 record = (byte*)rec;
00329 }
00330
00335 void* getRecord() {
00336 return record;
00337 }
00338
00343 bool isInSelection(oid_t oid);
00344
00345
00350 void fetch() {
00351 assert(!(db->currIndex[currId]
00352 & (dbInternalObjectMarker|dbFreeHandleMarker)));
00353 table->columns->fetchRecordFields(record,
00354 (byte*)db->getRow(currId));
00355 }
00356
00360 bool hasNext() const;
00361
00362 protected:
00363 dbDatabase* db;
00364 dbTableDescriptor* table;
00365 dbCursorType type;
00366 dbCursorType defaultType;
00367 dbSelection selection;
00368 bool allRecords;
00369 oid_t firstId;
00370 oid_t lastId;
00371 oid_t currId;
00372 byte* record;
00373 size_t limit;
00374
00375 int4* bitmap;
00376 size_t bitmapSize;
00377 bool eliminateDuplicates;
00378 bool prefetch;
00379 bool removed;
00380 bool lastRecordWasDeleted;
00381
00382 size_t stmtLimitStart;
00383 size_t stmtLimitLen;
00384 size_t nSkipped;
00385
00386 void* paramBase;
00387
00388 void checkForDuplicates();
00389 void deallocateBitmap();
00390
00391 bool isMarked(oid_t oid) {
00392 return bitmap != NULL && (bitmap[oid >> 5] & (1 << (oid & 31))) != 0;
00393 }
00394
00395 void setStatementLimit(dbQuery const& q) {
00396 stmtLimitStart = q.stmtLimitStartPtr != NULL ? (nat4)*q.stmtLimitStartPtr : q.stmtLimitStart;
00397 stmtLimitLen = q.stmtLimitLenPtr != NULL ? (nat4)*q.stmtLimitLenPtr : q.stmtLimitLen;
00398 }
00399
00400 void truncateSelection() {
00401 selection.truncate(stmtLimitStart, stmtLimitLen);
00402 }
00403
00404 void mark(oid_t oid) {
00405 if (bitmap != NULL) {
00406 bitmap[oid >> 5] |= 1 << (oid & 31);
00407 }
00408 }
00409
00410 bool add(oid_t oid) {
00411 if (selection.nRows < limit && selection.nRows < stmtLimitLen) {
00412 if (nSkipped < stmtLimitStart) {
00413 nSkipped += 1;
00414 return true;
00415 }
00416 if (eliminateDuplicates) {
00417 if (bitmap[oid >> 5] & (1 << (oid & 31))) {
00418 return true;
00419 }
00420 bitmap[oid >> 5] |= 1 << (oid & 31);
00421 }
00422 selection.add(oid);
00423 return selection.nRows < limit;
00424 }
00425 return false;
00426 }
00427
00428 bool gotoNext();
00429 bool gotoPrev();
00430 bool gotoFirst();
00431 bool gotoLast();
00432
00433 bool moveNext();
00434 bool movePrev();
00435
00436 void setCurrent(dbAnyReference const& ref);
00437
00438 void adjustReferences(size_t base, size_t size, long shift) {
00439 if (currId != 0 && record != NULL) {
00440 table->columns->adjustReferences(record, base, size, shift);
00441 }
00442 }
00443
00444 dbAnyCursor(dbTableDescriptor& aTable, dbCursorType aType, byte* rec)
00445 : table(&aTable),type(aType),defaultType(aType),
00446 allRecords(false),currId(0),record(rec)
00447 {
00448 db = aTable.db;
00449 limit = dbDefaultSelectionLimit;
00450 prefetch = rec != NULL;
00451 removed = false;
00452 bitmap = NULL;
00453 bitmapSize = 0;
00454 eliminateDuplicates = false;
00455 paramBase = NULL;
00456 stmtLimitLen = dbDefaultSelectionLimit;
00457 stmtLimitStart = 0;
00458 nSkipped = 0;
00459 }
00460 public:
00461 dbAnyCursor()
00462 : table(NULL),type(dbCursorViewOnly),defaultType(dbCursorViewOnly),
00463 allRecords(false),currId(0),record(NULL)
00464 {
00465 limit = dbDefaultSelectionLimit;
00466 prefetch = false;
00467 removed = false;
00468 bitmap = NULL;
00469 bitmapSize = 0;
00470 eliminateDuplicates = false;
00471 db = NULL;
00472 paramBase = NULL;
00473 stmtLimitLen = dbDefaultSelectionLimit;
00474 stmtLimitStart = 0;
00475 nSkipped = 0;
00476 }
00477 ~dbAnyCursor();
00478 };
00479
00480
00484 template<class T>
00485 class dbCursor : public dbAnyCursor {
00486 private:
00487
00488 dbCursor<T> operator = (dbCursor<T> const& src) {
00489 return *this;
00490 }
00491
00492 protected:
00493 T record;
00494
00495 public:
00500 dbCursor(dbCursorType type = dbCursorViewOnly)
00501 : dbAnyCursor(T::dbDescriptor, type, (byte*)&record) {}
00502
00509 dbCursor(dbDatabase* aDb, dbCursorType type = dbCursorViewOnly)
00510 : dbAnyCursor(T::dbDescriptor, type, (byte*)&record)
00511 {
00512 db = aDb;
00513 dbTableDescriptor* theTable = db->lookupTable(table);
00514 if (theTable != NULL) {
00515 table = theTable;
00516 }
00517 }
00518
00523 T* get() {
00524 return currId == 0 ? (T*)NULL : &record;
00525 }
00526
00531 T* next() {
00532 if (gotoNext()) {
00533 fetch();
00534 return &record;
00535 }
00536 return NULL;
00537 }
00538
00543 T* prev() {
00544 if (gotoPrev()) {
00545 fetch();
00546 return &record;
00547 }
00548 return NULL;
00549 }
00550
00555 T* first() {
00556 if (gotoFirst()) {
00557 fetch();
00558 return &record;
00559 }
00560 return NULL;
00561 }
00562
00567 T* last() {
00568 if (gotoLast()) {
00569 fetch();
00570 return &record;
00571 }
00572 return NULL;
00573 }
00574
00580 int seek(dbReference<T> const& ref) {
00581 return dbAnyCursor::seek(ref.getOid());
00582 }
00583
00588 T* operator ->() {
00589 assert(currId != 0);
00590 return &record;
00591 }
00592
00598 T* at(dbReference<T> const& ref) {
00599 setCurrent(ref);
00600 return &record;
00601 }
00602
00607 void toArray(dbArray< dbReference<T> >& arr) const {
00608 arr.resize(selection.nRows);
00609 toArrayOfOid((oid_t*)arr.base());
00610 }
00611
00616 dbReference<T> currentId() const {
00617 return dbReference<T>(currId);
00618 }
00619
00636 T* nextAvailable() {
00637 if (!removed) {
00638 return next();
00639 } else {
00640 removed = false;
00641 return lastRecordWasDeleted ? NULL : get();
00642 }
00643 }
00644
00662 T* prevAvailable() {
00663 if (!removed) {
00664 return prev();
00665 } else {
00666 removed = false;
00667 return lastRecordWasDeleted ? get() : prev();
00668 }
00669 }
00670
00675 bool isInSelection(dbReference<T>& ref) {
00676 return dbAnyCursor::isInSelection(ref.getOid());
00677 }
00678 };
00679
00680 class dbParallelQueryContext {
00681 public:
00682 dbDatabase* const db;
00683 dbCompiledQuery* const query;
00684 oid_t firstRow;
00685 dbTable* table;
00686 dbAnyCursor* cursor;
00687 dbSelection selection[dbMaxParallelSearchThreads];
00688
00689 void search(int i);
00690
00691 dbParallelQueryContext(dbDatabase* aDb, dbTable* aTable,
00692 dbCompiledQuery* aQuery, dbAnyCursor* aCursor)
00693 : db(aDb), query(aQuery), firstRow(aTable->firstRow), table(aTable), cursor(aCursor) {}
00694 };
00695
00696
00697 extern char* strupper(char* s);
00698
00699 extern char* strlower(char* s);
00700
00701 END_FASTDB_NAMESPACE
00702
00703 #endif