00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef __CURSOR_H__
00012 #define __CURSOR_H__
00013
00014 class dbOrderByNode;
00015
00016 class FASTDB_DLL_ENTRY dbSelection {
00017 public:
00018 enum { quantum = 1024 };
00019 class segment {
00020 public:
00021 segment* prev;
00022 segment* next;
00023 size_t nRows;
00024 oid_t rows[quantum];
00025
00026 segment(segment* after) {
00027 prev = after;
00028 next = NULL;
00029 nRows = 0;
00030 }
00031 };
00032 segment* first;
00033 segment* last;
00034 segment* curr;
00035 size_t nRows;
00036 size_t pos;
00037
00038 segment* createNewSegment(segment* after);
00039
00040 void add(oid_t oid) {
00041 if (last == NULL) {
00042 first = last = createNewSegment(NULL);
00043 } else if (last->nRows == quantum) {
00044 last = last->next = createNewSegment(last);
00045 }
00046 last->rows[last->nRows++] = oid;
00047 nRows += 1;
00048 }
00049
00050 void sort(dbDatabase* db, dbOrderByNode* order);
00051 static int compare(dbRecord* a, dbRecord* b, dbOrderByNode* order);
00052 static int compare(oid_t a, oid_t b, dbOrderByNode* order);
00053
00054 void toArray(oid_t* oids) const;
00055
00056 dbSelection() {
00057 nRows = 0;
00058 pos = 0;
00059 first = curr = last = NULL;
00060 }
00061 void reverse();
00062 void reset();
00063 };
00064
00065 enum dbCursorType {
00066 dbCursorViewOnly,
00067 dbCursorForUpdate
00068 };
00069
00073 class FASTDB_DLL_ENTRY dbAnyCursor : public dbL2List {
00074 friend class dbAnyContainer;
00075 friend class dbDatabase;
00076 friend class dbHashTable;
00077 friend class dbTtreeNode;
00078 friend class dbSubSql;
00079 friend class dbStatement;
00080 friend class dbServer;
00081 friend class dbCLI;
00082 public:
00087 int getNumberOfRecords() const { return selection.nRows; }
00088
00092 void remove();
00093
00098 bool isEmpty() const { return currId == 0; }
00099
00104 bool isUpdateCursor() const {
00105 return type == dbCursorForUpdate;
00106 }
00107
00112 bool isLimitReached() const { return selection.nRows >= limit; }
00113
00121 oid_t* toArrayOfOid(oid_t* arr) const;
00122
00133 int select(dbQuery& query, dbCursorType aType, void* paramStruct = NULL) {
00134 type = aType;
00135 reset();
00136 paramBase = paramStruct;
00137 db->select(this, query);
00138 paramBase = NULL;
00139 if (gotoFirst() && prefetch) {
00140 fetch();
00141 }
00142 return selection.nRows;
00143 }
00144
00151 int select(dbQuery& query, void* paramStruct = NULL) {
00152 return select(query, defaultType, paramStruct);
00153 }
00154
00162 int select(char const* condition, dbCursorType aType, void* paramStruct = NULL) {
00163 dbQuery query(condition);
00164 return select(query, aType, paramStruct);
00165 }
00166
00173 int select(char const* condition, void* paramStruct = NULL) {
00174 return select(condition, defaultType, paramStruct);
00175 }
00176
00182 int select(dbCursorType aType) {
00183 type = aType;
00184 reset();
00185 db->select(this);
00186 if (gotoFirst() && prefetch) {
00187 fetch();
00188 }
00189 return selection.nRows;
00190 }
00191
00196 int select() {
00197 return select(defaultType);
00198 }
00199
00206 int selectByKey(char const* key, void const* value);
00207
00215 int selectByKeyRange(char const* key, void const* minValue, void const* maxValue);
00216
00221 void update() {
00222 assert(type == dbCursorForUpdate && currId != 0);
00223 updateInProgress = true;
00224 db->update(currId, table, record);
00225 updateInProgress = false;
00226 }
00227
00231 void removeAll() {
00232 assert(db != NULL);
00233 db->deleteTable(table);
00234 reset();
00235 }
00236
00240 void removeAllSelected();
00241
00245 void setSelectionLimit(size_t lim) { limit = lim; }
00246
00250 void unsetSelectionLimit() { limit = dbDefaultSelectionLimit; }
00251
00258 void setPrefetchMode(bool mode) { prefetch = mode; }
00259
00263 void reset();
00264
00269 bool isLast() const;
00270
00275 bool isFirst() const;
00276
00282 void freeze();
00283
00287 void unfreeze();
00288
00296 bool skip(int n);
00297
00298
00304 int seek(oid_t oid);
00305
00309 dbTableDescriptor* getTable() { return table; }
00310
00311
00316 void setTable(dbTableDescriptor* aTable) {
00317 table = aTable;
00318 db = aTable->db;
00319 }
00320
00325 void setRecord(void* rec) {
00326 record = (byte*)rec;
00327 }
00328
00333 void* getRecord() {
00334 return record;
00335 }
00336
00341 bool isInSelection(oid_t oid);
00342
00343
00348 void fetch() {
00349 assert(!(db->currIndex[currId]
00350 & (dbInternalObjectMarker|dbFreeHandleMarker)));
00351 table->columns->fetchRecordFields(record,
00352 (byte*)db->getRow(currId));
00353 }
00354
00355
00356 protected:
00357 dbDatabase* db;
00358 dbTableDescriptor* table;
00359 dbCursorType type;
00360 dbCursorType defaultType;
00361 dbSelection selection;
00362 bool allRecords;
00363 oid_t firstId;
00364 oid_t lastId;
00365 oid_t currId;
00366 byte* record;
00367 size_t limit;
00368
00369 int4* bitmap;
00370 size_t bitmapSize;
00371 bool eliminateDuplicates;
00372 bool prefetch;
00373 bool removed;
00374 bool updateInProgress;
00375
00376 void* paramBase;
00377
00378 void checkForDuplicates();
00379
00380 bool isMarked(oid_t oid) {
00381 return bitmap != NULL && (bitmap[oid >> 5] & (1 << (oid & 31))) != 0;
00382 }
00383
00384 void mark(oid_t oid) {
00385 if (bitmap != NULL) {
00386 bitmap[oid >> 5] |= 1 << (oid & 31);
00387 }
00388 }
00389
00390 bool add(oid_t oid) {
00391 if (selection.nRows < limit) {
00392 if (eliminateDuplicates) {
00393 if (bitmap[oid >> 5] & (1 << (oid & 31))) {
00394 return true;
00395 }
00396 bitmap[oid >> 5] |= 1 << (oid & 31);
00397 }
00398 selection.add(oid);
00399 return selection.nRows < limit;
00400 }
00401 return false;
00402 }
00403
00404 bool gotoNext();
00405 bool gotoPrev();
00406 bool gotoFirst();
00407 bool gotoLast();
00408
00409 void setCurrent(dbAnyReference const& ref);
00410
00411 void adjustReferences(size_t base, size_t size, long shift) {
00412 if (currId != 0) {
00413 table->columns->adjustReferences(record, base, size, shift);
00414 }
00415 }
00416
00417 dbAnyCursor(dbTableDescriptor& aTable, dbCursorType aType, byte* rec)
00418 : table(&aTable),type(aType),defaultType(aType),
00419 allRecords(false),currId(0),record(rec)
00420 {
00421 db = aTable.db;
00422 limit = dbDefaultSelectionLimit;
00423 updateInProgress = false;
00424 prefetch = true;
00425 removed = false;
00426 bitmap = NULL;
00427 bitmapSize = 0;
00428 eliminateDuplicates = false;
00429 paramBase = NULL;
00430 }
00431 public:
00432 dbAnyCursor()
00433 : table(NULL),type(dbCursorViewOnly),defaultType(dbCursorViewOnly),
00434 allRecords(false),currId(0),record(NULL)
00435 {
00436 limit = dbDefaultSelectionLimit;
00437 updateInProgress = false;
00438 prefetch = false;
00439 removed = false;
00440 bitmap = NULL;
00441 bitmapSize = 0;
00442 eliminateDuplicates = false;
00443 db = NULL;
00444 paramBase = NULL;
00445 }
00446 ~dbAnyCursor();
00447 };
00448
00449
00453 template<class T>
00454 class dbCursor : public dbAnyCursor {
00455 protected:
00456 T record;
00457
00458 public:
00463 dbCursor(dbCursorType type = dbCursorViewOnly)
00464 : dbAnyCursor(T::dbDescriptor, type, (byte*)&record) {}
00465
00472 dbCursor(dbDatabase* aDb, dbCursorType type = dbCursorViewOnly)
00473 : dbAnyCursor(T::dbDescriptor, type, (byte*)&record)
00474 {
00475 db = aDb;
00476 dbTableDescriptor* theTable = db->lookupTable(table);
00477 if (theTable != NULL) {
00478 table = theTable;
00479 }
00480 }
00481
00486 T* get() {
00487 return currId == 0 ? (T*)NULL : &record;
00488 }
00489
00494 T* next() {
00495 if (gotoNext()) {
00496 fetch();
00497 return &record;
00498 }
00499 return NULL;
00500 }
00501
00506 T* prev() {
00507 if (gotoPrev()) {
00508 fetch();
00509 return &record;
00510 }
00511 return NULL;
00512 }
00513
00518 T* first() {
00519 if (gotoFirst()) {
00520 fetch();
00521 return &record;
00522 }
00523 return NULL;
00524 }
00525
00530 T* last() {
00531 if (gotoLast()) {
00532 fetch();
00533 return &record;
00534 }
00535 return NULL;
00536 }
00537
00543 int seek(dbReference<T> const& ref) {
00544 return dbAnyCursor::seek(ref.getOid());
00545 }
00546
00551 T* operator ->() {
00552 assert(currId != 0);
00553 return &record;
00554 }
00555
00561 T* at(dbReference<T> const& ref) {
00562 setCurrent(ref);
00563 return &record;
00564 }
00565
00570 void toArray(dbArray< dbReference<T> >& arr) const {
00571 arr.resize(selection.nRows);
00572 toArrayOfOid((oid_t*)arr.base());
00573 }
00574
00579 dbReference<T> currentId() const {
00580 return dbReference<T>(currId);
00581 }
00582
00599 T* nextAvailable() {
00600 if (!removed) {
00601 return next();
00602 } else {
00603 removed = false;
00604 return get();
00605 }
00606 }
00607
00612 bool isInSelection(dbReference<T>& ref) const {
00613 return dbAnyCursor::isInSelection(ref.getOid());
00614 }
00615 };
00616
00617 class dbParallelQueryContext {
00618 public:
00619 dbDatabase* const db;
00620 dbCompiledQuery* const query;
00621 oid_t firstRow;
00622 dbTable* table;
00623 dbAnyCursor* cursor;
00624 dbSelection selection[dbMaxParallelSearchThreads];
00625
00626 void search(int i);
00627
00628 dbParallelQueryContext(dbDatabase* aDb, dbTable* aTable,
00629 dbCompiledQuery* aQuery, dbAnyCursor* aCursor)
00630 : db(aDb), query(aQuery), firstRow(aTable->firstRow), table(aTable), cursor(aCursor) {}
00631 };
00632
00633
00634 extern char* strupper(char* s);
00635
00636 extern char* strlower(char* s);
00637
00638 #endif