00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef IXE_TABLE_H
00023 #define IXE_TABLE_H
00024
00025
00026 #include "platform.h"
00027
00028
00029 #include <sys/stat.h>
00030
00031
00032 #include "Store/tcbdb.h"
00033 #include "Store/tcfdb.h"
00034
00035
00036 #include "include/ixe.h"
00037 #include "include/error.h"
00038 #include "include/Enumerator.h"
00039 #include "Common/Lock.h"
00040 #include "Common/metaclass.h"
00041 #include "Common/util.h"
00042 #include "Index/Indexer.h"
00043 #include "io/File.h"
00044
00045 using namespace IXE::io;
00046
00048 inline bool tcbdbcurmatch(BDBCUR* dbc, const void* data, int size)
00049 {
00050 if (!tcbdbcurjump(dbc, data, size))
00051 return 0;
00052 int ksize;
00053 const void* kdata = tcbdbcurkey3(dbc, &ksize);
00054 return (ksize == size && !memcmp(kdata, data, size));
00055 }
00056
00057 namespace IXE {
00058
00065 char const Bext[] = "tcb";
00066 char const Hext[] = "tch";
00067 char const Fext[] = "tcf";
00068 char const Uext[] = "unv";
00069
00073 struct DBT {
00074 DBT() : data(0), size(0), len(0) { }
00075 DBT(int len) : data(calloc(len, 1)), size(0), len(len) { }
00076
00077 const void* data;
00078 int size;
00079 int len;
00080 };
00081
00082 bool realloc_record(DBT& record, ulong len);
00083 void fappend(char* f1, char* f2);
00084
00086
00088 void inline incrementKey(DBT& key_)
00089 {
00090 int n = key_.size, i = 0;
00091 byte* keyData = (byte*)key_.data;
00092 while (i < n && !++keyData[i++]) ;
00093 }
00094
00095 void inline decrementKey(DBT& key_)
00096 {
00097 int n = key_.size, i = 0;
00098 byte* keyData = (byte*)key_.data;
00099 while (i < n && !keyData[i++]--) ;
00100 }
00101
00102
00103
00110
00111
00112 class SubField {
00113 public:
00114 SubField(Field* field, TCBDB* table) :
00115 field(field), table(table) { }
00116
00117 Field* field;
00118 TCBDB* table;
00119 };
00120
00121
00129
00130
00131 class MappedSubField {
00132 public:
00133 MappedSubField(Field* field, mappedFile* table) :
00134 field(field), table(table) { }
00135
00136 Field* field;
00137 mappedFile* table;
00138 };
00139
00145 class SubCursor
00146 {
00147 public:
00148 SubCursor(TCBDB* db, MetaClass* mc) {
00149 cursor = tcbdbcurnew(db);
00150 mc->createInstance((byte*)obj);
00151 }
00152
00153 ~SubCursor() { tcbdbcurdel(cursor); }
00154
00155 private:
00156 BDBCUR* cursor;
00157 double obj[0];
00158 };
00159
00160
00167 struct NoDoc : std::unary_function<DocID, bool>
00168 {
00169 bool operator ()(DocID a) const { return false; }
00170 };
00171
00172 #define DocIDof(obj) (*(DocID*)FieldOf(obj, primaryField))
00173
00174
00188
00189
00190 class DynamicTable;
00191
00192 template <class T, class IndexerClass = TextIndexer>
00193 class Table : public Indexable<T>
00194 {
00195 friend class DynamicTable;
00196 friend class Cursor;
00197
00198 public:
00199
00200 typedef T ItemType;
00201 typedef Table<T, IndexerClass> TableType;
00202
00203 enum DbType {
00204 Btree,
00205 Hash,
00206 FixLen
00207 };
00208
00209 MetaClass* metaClass;
00210 IndexerClass* fulltextIndexer;
00211 std::vector<MappedSubField> mappedFields;
00212 std::vector<SubField> subFields;
00213
00214 char const* tableName() { return table_name; }
00215
00216 protected:
00217
00218 char const* table_name;
00219 # ifndef noMETADATA
00220 TCFDB* metadata;
00221 # endif
00222 TCBDB* primary;
00223 TCHDB* unique;
00224 std::vector<TCBDB*> keys;
00225 # ifdef FACETED_SEARCH
00226 std::vector<TCBDB*> facets;
00227 # endif
00228 DBT key;
00229 DBT row;
00230 ulonglong keyID;
00231 DocID lastID;
00232 bool isNew;
00233 Count nFulltext;
00234 Count nRows;
00235 Count nUnique;
00236 Field* autoincrementField;
00237 Field* externalField;
00238 Field* primaryField;
00239 Field* uniqueField;
00240 Size maxRowSize;
00241 bool master;
00242 DbType dbType;
00243
00244
00254 void open(char const* basename, bool readonly,
00255 DbType dbType, Size uniqueElements = 0,
00256 int cacheLeaves = 0, int cacheNodes = 0);
00257
00261 byte* mappedField(Field* fd, DocID id) {
00262 return (byte*)mappedFields[fd->position].table->begin() + (id - 1) * fd->itemSize();
00263 }
00264
00265 public:
00266
00276 Table(char const* pathname, bool readonly = false,
00277 MetaClass* meta = CLASS_OF(T),
00278 Size cacheSize = 0,
00279 DbType DBtype = Btree, Size uniqueElements = 0);
00280
00284 Table(Table const& table) :
00285 table_name(::strdup(table.table_name)),
00286 metaClass(table.metaClass),
00287 primary(table.primary),
00288 unique(table.unique),
00289 keys(table.keys),
00290 lastID(table.lastID),
00291 isNew(table.isNew),
00292 nFulltext(table.nFulltext),
00293 nRows(table.nRows),
00294 nUnique(table.nUnique),
00295 autoincrementField(table.autoincrementField),
00296 externalField(table.externalField),
00297 primaryField(table.primaryField),
00298 uniqueField(table.uniqueField),
00299 fulltextIndexer(table.fulltextIndexer),
00300 mappedFields(table.mappedFields),
00301 subFields(table.subFields),
00302 maxRowSize(table.maxRowSize),
00303 master(false)
00304 {
00305 Size keySize = table.key.len;
00306 key.data = (keySize <= sizeof(keyID)) ? (char *)&keyID : malloc(keySize);
00307 key.size = 0;
00308 key.len = keySize;
00309 }
00310
00314 Table(Table const& table, bool readonly) :
00315 table_name(::strdup(table.table_name)),
00316 metaClass(table.metaClass),
00317 isNew(false),
00318 master(false)
00319 {
00320 char const* filename = ::strrchr(table_name, PATH_SEPARATOR);
00321 string dirname(table_name, filename ? filename - table_name : 0);
00322 filename = filename ? filename + 1 : table_name;
00323 if (!dirname.empty() && !io::File(dirname).exists())
00324 throw TableError("Non existing directory: " + dirname);
00325
00326 open(filename, readonly, table.dbType);
00327 free((void*)filename);
00328 }
00329
00333 Table() { }
00334
00335 ~Table();
00336
00341 void noFulltextIndexing() {
00342 delete fulltextIndexer;
00343 fulltextIndexer = 0;
00344 }
00345
00349 void commit() {
00350 tcbdbsync(primary);
00351 vector<TCBDB*>::const_iterator index = keys.begin();
00352 for (Field* fd = this->metaClass->fields(); fd != NULL; fd = fd->next)
00353 if (fd->indexType & Field::indexed) {
00354 if (fd->indexType == Field::unique ||
00355 fd->indexType == Field::uniqueHash)
00356 tchdbsync((TCHDB*)*index);
00357 else
00358 tcbdbsync(*index);
00359 index++;
00360 }
00361 # ifdef FACETED_SEARCH
00362 for (std::vector<TCBDB*>::const_iterator fit = facets.begin();
00363 fit != facets.end();
00364 fit++)
00365 tcbdbsync(*fit);
00366 # endif
00367 if (fulltextIndexer)
00368 fulltextIndexer->commit();
00369 }
00370
00381 bool insert(ItemType* obj);
00382
00391 bool remove(ItemType* obj);
00392
00393
00394
00395 bool insertDynamic(AnyObject* obj);
00396
00400 void stopWords(StopWords* stopWords);
00401
00405 void stopWords(char const* fieldname, StopWords* stopWords);
00406
00411 T operator [](int i) const {
00412 Cursor cursor((TableType*)this);
00413 T* obj = cursor.get((DocID)i);
00414 return obj ? *obj : T();
00415 }
00416
00423 DocID getDocID(const char* field, const char* value);
00424
00430 DocID getDocID(ItemType* obj);
00431
00432 # ifndef noMETADATA
00433
00439 void Metadata(byte* obj, MetaClass* metadataClass);
00440
00448 void Metadata(MetaClass* metadataClass, byte* obj);
00449
00450 # endif
00451
00457 Count size() { return nRows; }
00458
00475 DocID merge(TableType* table2, Remap& remap) {
00476 return merge(table2, NoDoc(), remap);
00477 }
00478
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504 template<class DeleteTest>
00505 DocID merge(TableType* table2, DeleteTest delendum,
00506 Remap& remap) {
00507 TCBDB* primary2 = table2->Primary();
00508
00509 if (unique) {
00510
00511
00512
00513
00514 if (realloc_record(row, maxRowSize))
00515 throw MemoryError("Out of memory");
00516
00517 BDBCUR* cursor2 = tcbdbcurnew(primary2);
00518 for (bool hasNext = tcbdbcurfirst(cursor2);
00519 hasNext && (key.data = tcbdbcurkey3(cursor2, &key.size));
00520 hasNext = tcbdbcurnext(cursor2)) {
00521 DocID docID = *(DocID*)(key.data);
00522 if (!delendum(docID)) {
00523 ItemType obj;
00524 int row2Size;
00525 table2->fetch((byte*)&obj, (byte*)tcbdbcurval3(cursor2, &row2Size));
00526
00527
00528 DocID oldDocID = getDocID(&obj);
00529 if (oldDocID != noDocID) {
00530
00531
00532 remap[docID] = remap.size();
00533 } else {
00534
00535 DocIDof(&obj) = docID = ++lastID;
00536
00537 key.size = primaryField->storeKey((byte*)key.data, (byte*)&docID);
00538 insertRow(&obj);
00539 }
00540
00541 obj._clear();
00542 } else {
00543
00544
00545
00546 remap[docID] = remap.size();
00547 }
00548 }
00549 tcbdbcurdel(cursor2);
00550 } else {
00551
00552 DocID id_offset;
00553 LastID(&id_offset);
00554 BDBCUR* cursor2 = tcbdbcurnew(primary2);
00555 for (bool hasNext = tcbdbcurfirst(cursor2);
00556 hasNext && (key.data = tcbdbcurkey3(cursor2, &key.size));
00557 hasNext = tcbdbcurnext(cursor2)) {
00558 DocID docID = *(DocID*)(key.data);
00559 if (!delendum(docID)) {
00560 DBT row2;
00561 row2.data = (byte*)tcbdbcurval3(cursor2, &row2.size);
00562
00563 *(DocID*)(key.data) += id_offset;
00564 *(DocID*)(row2.data) += id_offset;
00565 tcbdbput(primary, key.data, key.size, row2.data, row2.size);
00566 lastID++;
00567 }
00568 }
00569 tcbdbcurdel(cursor2);
00570
00571
00572 int index = 0;
00573 int index2 = 0;
00574 int index3 = 0;
00575 for (Field* fd = this->metaClass->fields(); fd != NULL; fd = fd->next) {
00576
00577 if (fd->indexType & Field::indexed) {
00578 TCBDB* bdb = keys[index++];
00579 TCBDB* bdb2 = table2->Keys()[index2++];
00580 BDBCUR* scursor = tcbdbcurnew(bdb);
00581 BDBCUR* scursor2 = tcbdbcurnew(bdb2);
00582 for (bool hasNext = tcbdbcurfirst(scursor2);
00583 hasNext && (key.data = tcbdbcurkey3(scursor2, &key.size));
00584 hasNext = tcbdbcurnext(scursor2)) {
00585 DocID docID = *(DocID*)(key.data);
00586 if (!delendum(docID)) {
00587 DBT row2;
00588 row2.data = (byte*)tcbdbcurval3(scursor2, &row2.size);
00589
00590 *(DocID*)(key.data) += id_offset;
00591
00592 tcbdbputdup(bdb, row2.data, row2.size, key.data, key.size);
00593 } else {
00594
00595
00596
00597 remap[docID] = remap.size();
00598 }
00599 }
00600 tcbdbcurdel(scursor);
00601 tcbdbcurdel(scursor2);
00602 } else if (fd->indexType == Field::mapped) {
00603
00604
00605 char mapfile1[PATH_MAX];
00606 char mapfile2[PATH_MAX];
00607 sprintf(mapfile1, "%s/%s.%s", table_name, fd->name, Fext);
00608 sprintf(mapfile2, "%s/%s.%s", table2->table_name, fd->name, Fext);
00609 fappend(mapfile1, mapfile2);
00610 # ifdef FACETED_SEARCH
00611 } else if (fd->indexType == Field::facet) {
00612
00613
00614
00615
00616 TCBDB* bdb = Facets()[index3];
00617
00618 ColumnIndexer& ci = fulltextIndexer->indexer[fd->position];
00619 ci.partialCounts.push_back(tcbdbrnum(bdb));
00620 TCBDB* bdb2 = table2->Facets()[index3++];
00621 BDBCUR* cur2 = tcbdbcurnew(bdb2);
00622 byte* key;
00623 int klen;
00624 tcbdbcurfirst(cur2);
00625 while ((key = (byte*)tcbdbcurkey(cur2, &klen))) {
00626 int vlen;
00627 byte* value = (byte*)tcbdbcurval(cur2, &vlen);
00628 if (value && tcbdbvnum(bdb, key, klen) == 0)
00629 tcbdbput(bdb, key, klen, value, vlen);
00630 free(value);
00631 free(key);
00632 tcbdbcurnext(cur2);
00633 }
00634 tcbdbcurdel(cur2);
00635 # endif
00636 }
00637 }
00638 }
00639 return lastID;
00640 }
00641
00642 std::vector<TCBDB*>& Keys() { return keys; }
00643 # ifdef FACETED_SEARCH
00644 std::vector<TCBDB*>& Facets() { return facets; }
00645 # endif
00646 TCBDB* Primary() const { return primary; }
00647 DBT& Key() { return key; }
00648 Field* PrimaryField() const { return primaryField; }
00649 Size MaxRowSize() const { return maxRowSize; }
00650
00651
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666 class Cursor : public Enumerator<ItemType*> {
00667 protected:
00668 ItemType object;
00669 Table<ItemType, IndexerClass>* table;
00670
00671 DBT key_;
00672 DBT row_;
00673 Field* field;
00674 Field* fieldStart;
00675 Field* fieldEnd;
00676
00677 private:
00678 BDBCUR* dbc;
00679 TCBDB* db;
00680 ulonglong keyBuf;
00681 ulonglong rowBuf;
00682
00683 void init(Field* field) {
00684 fieldStart = table->metaClass->fields();
00685 fieldEnd = 0;
00686 if (field) {
00687 this->field = field;
00688
00689 std::vector<TCBDB*>::const_iterator keys = table->Keys().begin();
00690 for (Field* fd = table->metaClass->fields(); fd; fd = fd->next) {
00691 if (fd == field) {
00692 if (fd->indexType == Field::indexed) {
00693 db = *keys;
00694 break;
00695 } else
00696 throw TableError(string("Not an indexed field: ") + field->name);
00697 }
00698 }
00699 if (db) {
00700
00701
00702 Size fieldSize = field->maxLength() * field->size();
00703 if (fieldSize <= sizeof(keyBuf))
00704 key_.data = (char*)&keyBuf;
00705
00706 else if (realloc_record(key_, fieldSize))
00707 throw MemoryError("Out of memory");
00708 key_.size = key_.len = fieldSize;
00709
00710 Size rowSize = table->Key().len;
00711 row_.data = (rowSize <= sizeof(rowBuf)) ?
00712 (char*)&rowBuf : (char*)malloc(rowSize);
00713 row_.size = row_.len = rowSize;
00714 } else
00715 throw TableError(string("No such field: ") + field->name);
00716 } else {
00717 this->field = table->PrimaryField();
00718 db = table->Primary();
00719 Size keySize = table->Key().len;
00720
00721 if (realloc_record(row_, table->maxRowSize))
00722 throw MemoryError("Out of memory");
00723 row_.size = 0;
00724 row_.len = table->maxRowSize;
00725
00726 key_.data = (keySize <= sizeof(keyBuf)) ?
00727 (char*)&keyBuf : (char*)malloc(keySize);
00728 ::memset((void*)key_.data, 0, keySize);
00729 key_.size = key_.len = keySize;
00730 }
00731 dbc = tcbdbcurnew(db);
00732 }
00733
00734 public:
00735
00741 Cursor(TableType* table, Field* field = 0) : table(table) {
00742 init(field);
00743 }
00744
00750 Cursor(TableType* table, char const* name) : table(table) {
00751 init(table->metaClass->find(name));
00752 }
00753
00754 ~Cursor() {
00755 tcbdbcurdel(dbc);
00756 if (key_.data != &keyBuf)
00757 free((void*)key_.data);
00758 if (row_.data != &rowBuf)
00759 free((void*)row_.data);
00760
00761 object._clear();
00762 }
00763
00769 void setKey(int8 const value) {
00770 field->setKey((byte*)key_.data, value);
00771 }
00772
00773 void setKey(char const* value) {
00774 field->setKey((byte*)key_.data, (byte*)value, (Size&)key_.size, (Size)key_.len);
00775 }
00776
00777 void setKey(byte const* value) {
00778 field->setKey((byte*)key_.data, value, (Size&)key_.size, (Size)key_.len);
00779 }
00780
00784 DocID getKey() {
00785 DocID docID;
00786 field->fetchKey((byte*)&docID, (byte*)row_.data);
00787 return docID;
00788 }
00789
00794 void getPrimaryKey(byte* key) {
00795 table->primaryField->fetchKey(key, getRowData());
00796 }
00797
00802 byte* fetchRowData() {
00803 DBT row;
00804 row.data = tcbdbcurval3(dbc, &row.size);
00805 memcpy((void*)row_.data, row.data, row.size);
00806 row_.size = row.size;
00807 return (byte*)row_.data;
00808 }
00809
00820 bool MoveNext() {
00821
00822 if ((dbc->id < 1) ? tcbdbcurfirst(dbc) : tcbdbcurnext(dbc)) {
00823 fetchRowData();
00824 return true;
00825 }
00826 return false;
00827 }
00828
00832 byte* NextSame() {
00833 if (dbc->id < 1) {
00834
00835 if (!tcbdbcurjump(dbc, key_.data, key_.size))
00836 return 0;
00837 } else if (!tcbdbcurnext(dbc))
00838 return 0;
00839 DBT next;
00840 next.data = tcbdbcurkey3(dbc, &next.size);
00841 return (key_.size == next.size && !memcmp(key_.data, next.data, next.size)) ?
00842 fetchRowData() : 0;
00843 }
00844
00851 T* first() {
00852 return tcbdbcurfirst(dbc) ? get() : 0;
00853 }
00854
00861 T* last() {
00862 return tcbdbcurlast(dbc) ? get() : 0;
00863 }
00864
00871 T* previous() {
00872 return tcbdbcurprev(dbc) ? get() : 0;
00873 }
00874
00881 virtual T* get() {
00882 if (field != table->PrimaryField()) {
00883
00884 TCBDB* dbp = table->Primary();
00885 const void* row;
00886 int rowSize;
00887 if (!(row = tcbdbget3(dbp, row_.data, row_.size, &rowSize)))
00888 return 0;
00889
00890 if (realloc_record(row_, rowSize))
00891 throw MemoryError("Out of memory");
00892 ::memcpy((void*)row_.data, row, rowSize);
00893 row_.size = rowSize;
00894 } else
00895 fetchRowData();
00896 byte* value = (byte*)row_.data;
00897 DocID id;
00898 getPrimaryKey((byte*)&id);
00899 for (Field* fd = fieldStart; fd != fieldEnd; fd = fd->next) {
00900 byte* field = FieldOf(&object, fd);
00901 if (fd->isReference()) {
00902 if (fd->indexType == Field::mapped) {
00903 byte* mf = table->mappedField(fd, id);
00904 fd->fetch(field, mf);
00905 } else {
00906
00907 FOR_EACH (std::vector<SubField>, table->subFields, sit) {
00908 if (sit->field == fd) {
00909 Field* sf = sit->field;
00910 TCBDB* dbp = sit->table;
00911 const void* subField;
00912 int subFieldSize;
00913 if (!(subField = tcbdbget3(dbp, &id, sizeof(id), &subFieldSize)))
00914 throw TableError(string("Failed fetching field from: ")
00915 + sf->name);
00916 sf->fetch((byte*)subField, value);
00917 break;
00918 }
00919 }
00920 }
00921 } else
00922 fd->fetch(field, value);
00923 }
00924 return &object;
00925 }
00926
00931 byte* getKeyData() { return key_.data; }
00932
00937 byte* getRowData() { return (byte*)row_.data; }
00938
00944 int size() const {
00945 return tcbdbvnum(db, key_.data, key_.size);
00946 }
00947
00951 byte* getNext() {
00952 return ((dbc->id < 1) ? tcbdbcurfirst(dbc) : tcbdbcurnext(dbc)) ?
00953 fetchRowData() : 0;
00954 }
00955
00959 byte* getPrevious() {
00960 return tcbdbcurprev(dbc) ? fetchRowData() : 0;
00961 }
00962
00971 T* get(DocID docID) {
00972 field->setKey((byte*)key_.data, docID);
00973 return tcbdbcurmatch(dbc, key_.data, key_.size) ? get() : 0;
00974 }
00975
00985 T* get(byte const* key) {
00986 setKey(key);
00987 return tcbdbcurmatch(dbc, key_.data, key_.size) ? get() : 0;
00988 }
00989
00994 T* get(ItemType* obj) {
00995 byte* key = FieldOf(obj, field);
00996 return get(key);
00997 }
00998
01006 byte* getEQ() {
01007 return tcbdbcurmatch(dbc, key_.data, key_.size) ? fetchRowData() : 0;
01008 }
01009
01017 byte* getGE() {
01018 return tcbdbcurjump(dbc, key_.data, key_.size) ? fetchRowData() : 0;
01019 }
01020
01028 byte* getGT() {
01029
01030 incrementKey(key_);
01031 return tcbdbcurjump(dbc, key_.data, key_.size) ? fetchRowData() : 0;
01032 }
01033
01041 byte* getLE() {
01042 return tcbdbcurjumpback(dbc, key_.data, key_.size) ? fetchRowData() : 0;
01043 }
01044
01052 byte* getLT() {
01053
01054 decrementKey(key_);
01055 return tcbdbcurjumpback(dbc, key_.data, key_.size) ? fetchRowData() : 0;
01056 }
01057
01062 ItemType* operator ->() { return &object; }
01063
01067 bool update() {
01068 Field* primaryField = table->PrimaryField();
01069
01070 DBT& key = table->Key();
01071 key.size = primaryField->storeKey((byte*)key.data,
01072 FieldOf(&object, primaryField));
01073 table->insertRow(&object);
01074 return true;
01075 }
01076 };
01077
01081 DocID LastID() { return lastID; }
01082
01087 void LastID(DocID lastID) { this->lastID = lastID; }
01088
01089 protected:
01090 Lock mutex;
01091
01092 void close();
01093
01097 void LastID(DocID* lastID) {
01098 Cursor cursor(this);
01099 if (cursor.last())
01100 *lastID = cursor.getKey();
01101 }
01102
01103 void fetch(byte* obj, byte* row) {
01104 DocID docID;
01105 if (!mappedFields.empty())
01106 primaryField->fetchKey((byte*)&docID, row);
01107
01108 for (Field* fd = metaClass->fields(); fd; fd = fd->next) {
01109 byte* field = FieldOf(obj, fd);
01110 if (fd->indexType == Field::mapped) {
01111 byte* mf = mappedField(fd, docID);
01112 fd->fetch(field, mf);
01113 } else
01114 fd->fetch(field, row);
01115 }
01116 }
01117
01123 void removeSecondary(ItemType const& obj);
01124
01128 void insertRow(ItemType* obj);
01129 };
01130
01131
01137
01138
01139 class DynamicTable : public Table<AnyObject>
01140 {
01141 public:
01142
01143 DynamicTable(char const* table_name, MetaClass* metaClass,
01144 bool readonly = true) :
01145 Table<AnyObject>(table_name, readonly, metaClass) { }
01146
01147 bool insert(AnyObject* obj);
01148
01149 class Cursor : public Table<AnyObject>::Cursor
01150 {
01151 public:
01152 Cursor(DynamicTable* table, Field* field = 0) :
01153 Table<AnyObject>::Cursor(table, field) {
01154 object = AnyObject(table->metaClass);
01155 }
01156
01157 virtual AnyObject* get() {
01158 if (field != table->PrimaryField()) {
01159
01160 TCBDB* dbp = table->Primary();
01161 const void* row;
01162 int rowSize;
01163 if (!(row = tcbdbget3(dbp, row_.data, row_.size, &rowSize)))
01164 return 0;
01165
01166 if (realloc_record(row_, rowSize))
01167 throw MemoryError("Out of memory");
01168 ::memcpy((void*)row_.data, row, rowSize);
01169 row_.size = rowSize;
01170 } else
01171 fetchRowData();
01172 byte* field = (byte*)row_.data;
01173 std::vector<Item*>::const_iterator item = object.values.begin();
01174 Field* fd = table->metaClass->fields();
01175 for ( ; fd != fieldStart; fd = fd->next)
01176 item++;
01177 for ( ; fd != fieldEnd; fd = fd->next)
01178 field = fd->fetch((*item++)->value(), field);
01179 return &object;
01180 }
01181 };
01182 };
01183
01184 }
01185
01186
01187 # ifndef NON_TEMPLATE
01188 # include "table.cpp"
01189 # endif
01190
01191 #endif // IXE_TABLE_H