Collection.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
00022 */
00023 
00024 
00025 // 15/08/06 : avoid use of exists method
00026 #define NEW_GET_ELEMENTS
00027 
00028 #include "eyedb_p.h"
00029 #include "ValueCache.h"
00030 #include "CollectionBE.h"
00031 #include <assert.h>
00032 #include "AttrNative.h"
00033 #include "Attribute_p.h"
00034 
00035 #define NEW_MASTER_OBJ
00036 
00037 #define TRY_GETELEMS_GC
00038 
00039 //#define INIT_IDR
00040 
00041 static bool eyedb_support_stack = getenv("EYEDB_SUPPORT_STACK") ? true : false;
00042 
00043 using namespace std;
00044 
00045 namespace eyedb {
00046 
00047   static Offset LITERAL_OFFSET;
00048 
00049   extern int
00050   get_item_size(const Class *coll_class, int dim);
00051 
00052   static Bool collupd_noopt = getenv("EYEDB_COLLUPD_NOOPT") ? True : False;
00053 
00054 #define CACHE_LIST(C)       ((C) ? (C)->getList() : (LinkedList *)0)
00055 #define CACHE_LIST_COUNT(C) ((C) ? (C)->getIdMap().size() : 0)
00056 
00057   // WARNING: the optimisation for create makes a problem in the
00058   // inverses! => 
00059 #define COLL_OPTIM_CREATE
00060 #define COLL_OPTIM_LOAD
00061 
00062 #define COLL_REENTRANT
00063   //#define COLL_SIZE_MAX     0x400
00064 
00065   //#define COLLTRACE
00066 
00067   const Size Collection::defaultSize = (Size)-1;
00068 
00069   //
00070   // Collection init method
00071   //
00072 
00073   static inline IndexImpl *
00074   getDefaultIndexImpl()
00075   {
00076     static IndexImpl *defIndexImpl;
00077     if (!defIndexImpl)
00078       defIndexImpl = new IndexImpl(IndexImpl::Hash, 0, 0, 0, 0, 0);
00079     return defIndexImpl;
00080   }
00081 
00082   void Collection::_init(const IndexImpl *_idximpl)
00083   {
00084     if (isref || !coll_class)
00085       item_size = sizeof(Oid);
00086     else
00087       item_size = get_item_size(coll_class, dim);
00088 
00089     Exception::Mode mode = Exception::setMode(Exception::StatusMode);
00090 
00091 #if 0
00092     if (item_size > COLL_SIZE_MAX)
00093       status = Exception::make(IDB_COLLECTION_ITEM_SIZE_TOO_LARGE,
00094                                "collection '%s', item size is '%d', "
00095                                "max size is '%d'",
00096                                name, item_size, COLL_SIZE_MAX);
00097     else
00098 #endif
00099     if (item_size == 0)
00100       status = Exception::make(IDB_COLLECTION_ITEM_SIZE_UNKNOWN,
00101                                "collection '%s'", name);
00102     else
00103       status = Success;
00104 
00105     Exception::setMode(mode);
00106 
00107     cache = 0;
00108 
00109     read_cache.obj_arr = 0;
00110     read_cache.oid_arr = 0;
00111     read_cache.val_arr = 0;
00112 
00113     read_cache_state_oid = read_cache_state_value = read_cache_state_object = coherent;
00114     read_cache_state_index = False;
00115     locked = False;
00116     if (!_idximpl)
00117       _idximpl = getDefaultIndexImpl();
00118 
00119     idximpl = _idximpl->clone();
00120     isStringColl();
00121     card = NULL;
00122     card_oid.invalidate();
00123     bottom = top = 0;
00124     inv_oid.invalidate();
00125     inv_item = 0;
00126     inverse_valid = True;
00127     literal_oid.invalidate();
00128     is_literal = False;
00129     is_pure_literal = False;
00130     is_complete = True;
00131     idx_data = 0;
00132     idx_data_size = 0;
00133     implModified = False;
00134 #ifdef INIT_IDR
00135     inv_oid_offset = 0;
00136     init_idr();
00137 #endif
00138   }
00139 
00140   void
00141   Collection::unvalidReadCache()
00142   {
00143     read_cache_state_oid = read_cache_state_object = read_cache_state_value = modified;
00144     read_cache_state_index = False;
00145   }
00146 
00147 #define DEFMAGORDER 4
00148   static int
00149   getMagorder(const IndexImpl *idximpl)
00150   {
00151     if (idximpl)
00152       return idximpl->getMagorder(DEFMAGORDER);
00153     return DEFMAGORDER;
00154   }
00155 
00156   void
00157   Collection::create_cache()
00158   {
00159     if (!cache)
00160       cache = new ValueCache(this);
00161   }
00162 
00163   void
00164   Collection::isStringColl()
00165   {
00166     if (!strcmp(coll_class->getName(), char_class_name) && dim > 1)
00167       string_coll = True;
00168     else
00169       string_coll = False;
00170   }
00171 
00172   void Collection::decode(Data data) const
00173   {
00174     Offset offset = 0;
00175     if (isref) {
00176       eyedbsm::Oid smoid;
00177       oid_decode(data, &offset, &smoid);
00178       memcpy(data, &smoid, sizeof(smoid));
00179     }
00180     else if (coll_class->asInt16Class()) {
00181       eyedblib::int16 i16;
00182       int16_decode(data, &offset, &i16);
00183       memcpy(data, &i16, sizeof(i16));
00184     }
00185     else if (coll_class->asInt32Class()) {
00186       eyedblib::int32 i32;
00187       int32_decode(data, &offset, &i32);
00188       memcpy(data, &i32, sizeof(i32));
00189     }
00190     else if (coll_class->asInt64Class()) {
00191       eyedblib::int64 i64;
00192       int64_decode(data, &offset, &i64);
00193       memcpy(data, &i64, sizeof(i64));
00194     }
00195     else if (coll_class->asFloatClass()) {
00196       double d;
00197       double_decode(data, &offset, &d);
00198       memcpy(data, &d, sizeof(d));
00199     }
00200   }
00201 
00202   Data Collection::make_data(Data data, Size size, Bool swap) const
00203   {
00204     if (size == defaultSize)
00205       size = item_size;
00206 
00207     if (size < 0 || size > item_size)
00208       return 0;
00209 
00210     Data item_data;
00211 
00212     item_data = (unsigned char *)malloc(item_size);
00213 
00214     if (string_coll) {
00215       int len = strlen((char *)data);
00216 
00217       if (len >= item_size) {
00218         free(item_data);
00219         return 0;
00220       }
00221       
00222       strcpy((char *)item_data, (char *)data);
00223       memset((char *)item_data+len, 0, item_size-len);
00224     }
00225     else if (swap) {
00226       if (isref)
00227         oid_code(item_data, data);
00228       else if (coll_class->asInt16Class())
00229         int16_code(item_data, data);
00230       else if (coll_class->asInt32Class())
00231         int32_code(item_data, data);
00232       else if (coll_class->asInt64Class())
00233         int64_code(item_data, data);
00234       else if (coll_class->asFloatClass())
00235         double_code(item_data, data);
00236       else { // byte class
00237         memcpy(item_data, data, size);
00238         
00239         if (size < item_size)
00240           memset(item_data+size, 0, item_size-size);
00241       }
00242     }
00243     else {
00244       memcpy(item_data, data, size);
00245 
00246       if (size < item_size)
00247         memset(item_data+size, 0, item_size-size);
00248     }
00249 
00250     return item_data;
00251   }
00252 
00253   Status
00254   Collection::realizeInverse(const Oid& _inv_oid, int _inv_item)
00255   {
00256     setInverse(_inv_oid, _inv_item);
00257 
00258     //  printf("realizeInverse(%s, %p)\n", inv_oid.toString(), inv_item);
00259     if (!inv_oid.isValid())
00260       return Success;
00261 
00262     if (status != Success)
00263       return Exception::make(IDB_COLLECTION_ERROR,
00264                              "invalid collection status: \"%s\"",
00265                              status->getDesc());
00266 
00267     if (!getOidC().isValid())
00268       return Exception::make(IDB_COLLECTION_ERROR, "collection oid '%s' is not valid", name);
00269 
00270     Data temp = 0;
00271     Offset offset = IDB_OBJ_HEAD_SIZE;
00272     Size alloc_size = 0;
00273 
00274     oid_code(&temp, &offset, &alloc_size, inv_oid.getOid());
00275     int16_code(&temp, &offset, &alloc_size, &inv_item);
00276 
00277     ObjectHeader hdr;
00278     memset(&hdr, 0, sizeof(hdr));
00279 
00280     hdr.type = type;
00281     hdr.size = alloc_size;
00282     hdr.xinfo = IDB_XINFO_INV;
00283 
00284     offset = 0;
00285 
00286     object_header_code(&temp, &offset, &alloc_size, &hdr);
00287 
00288     RPCStatus rpc_status;
00289 
00290     rpc_status = objectWrite(db->getDbHandle(), temp, getOidC().getOid());
00291 
00292     free(temp);
00293 
00294     return StatusMake(IDB_COLLECTION_ERROR, rpc_status);
00295   }
00296 
00297   void
00298   Collection::setInverse(const Oid& _inv_oid, int _inv_item)
00299   {
00300     //  printf("Collection::setInverse(%s)\n", _inv_oid.toString());
00301     inv_oid = _inv_oid;
00302     inv_item = _inv_item;
00303   }
00304 
00305   void Collection::setCardinalityConstraint(Object *_card)
00306   {
00307 #ifdef CARD_TRACE
00308     printf("Collection::setCardinalityConstraint(%p)\n", _card);
00309 #endif
00310     if (!_card)
00311       {
00312         card = NULL;
00313         card_oid.invalidate();
00314         return;
00315       }
00316 
00317     if (!strcmp(_card->getClass()->getName(), "cardinality_constraint"))
00318       {
00319         card = ((CardinalityConstraint *)_card)->getCardDesc();
00320         if (!card)
00321           {
00322             card_oid.invalidate();
00323             return;
00324           }
00325       }
00326     else
00327       card = (CardinalityDescription *)_card;
00328   
00329     card_oid = _card->getOid();
00330     card_bottom = card->getBottom();
00331     card_bottom_excl = card->getBottomExcl();
00332     card_top = card->getTop();
00333     card_top_excl = card->getTopExcl();
00334   }
00335 
00336   CardinalityDescription *Collection::getCardinalityConstraint() const
00337   {
00338     return card;
00339   }
00340 
00341   //
00342   // Collection constructors
00343   //
00344 
00345   Collection::Collection(const char *n, Class *_class,
00346                          const Oid& _idx1_oid,
00347                          const Oid& _idx2_oid,
00348                          int icnt,
00349                          int _bottom, int _top,
00350                          const IndexImpl *_idximpl,
00351                          Object *_card, Bool _is_literal, Bool _is_pure_literal,
00352                          Data _idx_data, Size _idx_data_size) :
00353     Instance()
00354   {
00355     name = strdup(n);
00356     p_items_cnt = icnt;
00357     v_items_cnt = icnt;
00358     setClass(_class);
00359     bottom = _bottom;
00360     top = _top;
00361     setCardinalityConstraint(_card);
00362     coll_class = getClass()->asCollectionClass()->getCollClass(&isref,
00363                                                                &dim,
00364                                                                &item_size);
00365     if (dim <= 0) {
00366       Exception::Mode mode = Exception::setMode(Exception::StatusMode);
00367       status = Exception::make(IDB_COLLECTION_ERROR, "invalid dimension: %d\n", dim);
00368       Exception::setMode(mode);
00369       return;
00370     }
00371 
00372     idx1_oid = _idx1_oid;
00373     idx2_oid = _idx2_oid;
00374   
00375     status = Success;
00376 
00377     locked = False;
00378 
00379     if (!_idximpl)
00380       _idximpl = getDefaultIndexImpl();
00381     idximpl = _idximpl->clone();
00382     cache = 0;
00383 
00384     unvalidReadCache();
00385 
00386     read_cache.obj_arr = 0;
00387     read_cache.oid_arr = 0;
00388     read_cache.val_arr = 0;
00389 
00390     isStringColl();
00391     inv_oid.invalidate();
00392     inv_item = 0;
00393     inverse_valid = True;
00394     literal_oid.invalidate();
00395     is_literal = _is_literal;
00396     is_pure_literal = _is_pure_literal;
00397     is_complete = True;
00398     idx_data_size = _idx_data_size;
00399     idx_data = (idx_data_size ? (Data)malloc(idx_data_size) : 0);
00400     memcpy(idx_data, _idx_data, idx_data_size);
00401     implModified = False;
00402 #ifdef INIT_IDR
00403     inv_oid_offset = 0;
00404     init_idr();
00405 #endif
00406 
00407 #ifdef COLLTRACE
00408     printf("Collection[%p] -> %s\n", this,
00409            (const char *)AttrIdxContext(idx_data, idx_data_size).getString());
00410 #endif
00411   }
00412 
00413   void Collection::make(const char *n, Class *mc, Bool _isref,
00414                         const IndexImpl *_idximpl)
00415   {
00416     name = strdup(n);
00417     p_items_cnt = 0;
00418     v_items_cnt = 0;
00419     coll_class = (mc ? mc : Object_Class);
00420     isref = _isref;
00421     dim = 1;
00422 
00423     status = Success;
00424 
00425     _init(_idximpl);
00426   }
00427 
00428   void Collection::make(const char *n, Class *mc, int _dim,
00429                         const IndexImpl *_idximpl)
00430   {
00431     name = strdup(n);
00432     p_items_cnt = 0;
00433     v_items_cnt = 0;
00434     coll_class = (mc ? mc : Object_Class);
00435     isref = False;
00436     dim = _dim;
00437 
00438     if (dim <= 0) {
00439       Exception::Mode mode = Exception::setMode(Exception::StatusMode);
00440       status = Exception::make(IDB_COLLECTION_ERROR, "invalid dimension: %d\n", dim);
00441       Exception::setMode(mode);
00442       return;
00443     }
00444 
00445     status = Success;
00446 
00447     _init(_idximpl);
00448   }
00449 
00450   Collection::Collection(const char *n, Class *mc, Bool _isref,
00451                          const IndexImpl *_idximpl) : Instance()
00452   {
00453     make(n, mc, _isref, _idximpl);
00454   }
00455 
00456   Collection::Collection(const char *n, Class *mc, int _dim,
00457                          const IndexImpl *_idximpl) : Instance()
00458   {
00459     make(n, mc, _dim, _idximpl);
00460   }
00461 
00462   Collection::Collection(const Collection &coll) : Instance(coll)
00463   {
00464     name = 0;
00465     cache = 0;
00466     idx_data = 0;
00467     idx_data_size = 0;
00468     memset(&read_cache, 0, sizeof(ReadCache));
00469     status = Success;
00470     idximpl = 0;
00471     *this = coll;
00472   }
00473 
00474 #define CLONE(X) ((X) ? (X)->clone() : 0)
00475 #define STRDUP(X) ((X) ? strdup(X) : 0)
00476 
00477 #ifndef NEW_MASTER_OBJ
00478   static Object *
00479   get_master_object(Object *o)
00480   {
00481     if (!o) return 0;
00482 
00483     if (o->getMasterObject())
00484       return get_master_object(o->getMasterObject());
00485 
00486     return o;
00487   }
00488 #endif
00489 
00490   void
00491   Collection::setImplementation(const IndexImpl *_idximpl)
00492   {
00493     if (!idximpl->compare(_idximpl)) {
00494       if (idximpl)
00495         idximpl->release();
00496       idximpl = _idximpl->clone();
00497 #ifdef NEW_MASTER_OBJ
00498       if (is_literal && getMasterObject(true))
00499         getMasterObject(true)->touch();
00500 #else
00501       if (is_literal && getMasterObject())
00502         get_master_object(getMasterObject())->touch();
00503 #endif
00504       touch();
00505       implModified = True;
00506     }
00507   }
00508 
00509   Collection& Collection::operator=(const Collection &coll)
00510   {
00511     //garbage(); // will be done in Object::operator=
00512 
00513     *(Object *)this = (const Object &)coll;
00514     type = coll.type;
00515     name = STRDUP(coll.name);
00516     ordered = coll.ordered;
00517     allow_dup = coll.allow_dup;
00518     string_coll = coll.string_coll;
00519     bottom = coll.bottom;
00520     top = coll.top;
00521   
00522     coll_class = coll.coll_class;
00523 
00524     isref = coll.isref;
00525     dim = coll.dim;
00526     item_size = coll.item_size;
00527     cl_oid = coll.cl_oid;
00528   
00529     locked = coll.locked;
00530     idximpl = coll.idximpl->clone();
00531     inv_oid = coll.inv_oid;
00532     inv_item = coll.inv_item;
00533   
00534     card = (CardinalityDescription *)CLONE(coll.card);
00535     card_bottom = coll.card_bottom;
00536     card_bottom_excl = coll.card_bottom_excl;
00537     card_top = coll.card_top;
00538     card_top_excl = coll.card_top_excl;
00539     card_oid = coll.card_oid;
00540 
00541     idx1_oid = coll.idx1_oid;
00542     idx2_oid = coll.idx2_oid;
00543     idx1 = coll.idx1;
00544     idx2 = coll.idx2;
00545     p_items_cnt = coll.p_items_cnt;
00546     v_items_cnt = coll.v_items_cnt;
00547     inverse_valid = coll.inverse_valid;
00548     is_literal = coll.is_literal;
00549     is_pure_literal = coll.is_pure_literal;
00550     is_complete = coll.is_complete;
00551     literal_oid = coll.literal_oid;
00552     idx_data_size = coll.idx_data_size;
00553     idx_data = (idx_data_size ? (Data)malloc(idx_data_size) : 0);
00554     memcpy(idx_data, coll.idx_data, idx_data_size);
00555 
00556     // should copy the cache???
00557     cache = 0;
00558 
00559     read_cache.obj_arr = 0;
00560     read_cache.oid_arr = 0;
00561     read_cache.val_arr = 0;
00562 
00563     return *this;
00564   }
00565 
00566   Status Collection::setDatabase(Database *mdb)
00567   {
00568     if (mdb == db)
00569       return Success;
00570 
00571     Database *odb = db;
00572 
00573     if (odb && odb != mdb)
00574       {
00575         assert(0);
00576         return Exception::make(IDB_ERROR, "cannot change dynamically database of an object");
00577       }
00578 
00579     db = mdb;
00580 
00581     Class *_cls = getClass();
00582     Status s = CollectionClass::make(db, &_cls);
00583     if (!s)
00584       setClass(_cls);
00585     return s;
00586   }
00587 
00588   void Collection::setLiteral(Bool _is_literal)
00589   {
00590     is_literal = _is_literal;
00591   }
00592 
00593   void Collection::setPureLiteral(Bool _is_pure_literal)
00594   {
00595     is_pure_literal = _is_pure_literal;
00596   }
00597 
00598   char Collection::codeLiteral() const
00599   {
00600     if (is_pure_literal)
00601       return CollPureLiteral;
00602 
00603     if (is_literal)
00604       return CollLiteral;
00605 
00606     return CollObject;
00607   }
00608 
00609   void Collection::decodeLiteral(char c, Bool &is_literal, Bool &is_pure_literal)
00610   {
00611     if (c == CollPureLiteral) {
00612       is_pure_literal = True;
00613       is_literal = True;
00614     }
00615     else if (c == CollLiteral) {
00616       is_pure_literal = False;
00617       is_literal = True;
00618     }
00619     else {
00620       is_pure_literal = False;
00621       is_literal = False;
00622     }
00623   }
00624 
00625   Status Collection::loadLiteral()
00626   {
00627     unsigned char data[1];
00628     short dspid = 0;
00629     Oid toid = literal_oid;
00630     if (!toid.isValid())
00631       toid = getOid();
00632       
00633     if (!toid.isValid())
00634       return Success;
00635 
00636     RPCStatus rpc_status = dataRead(db->getDbHandle(), LITERAL_OFFSET,
00637                                     sizeof(char),
00638                                     data, &dspid, toid.getOid());
00639     if (rpc_status)
00640       return StatusMake(rpc_status);
00641 
00642     Offset offset = 0;
00643     char c;
00644     char_decode (data, &offset, &c);
00645     Collection::decodeLiteral(c, is_literal, is_pure_literal);
00646 
00647     return Success;
00648   }
00649 
00650   Status Collection::updateLiteral()
00651   {
00652     if (db) {
00653       char new_code = codeLiteral();
00654 
00655       Oid toid = literal_oid;
00656       if (!toid.isValid())
00657         toid = getOid();
00658       
00659       if (toid.isValid()) {
00660         Offset offset = 0;
00661         Size alloc_size = sizeof(char);
00662         unsigned char data[1];
00663         unsigned char *pdata = data;
00664         char_code(&pdata, &offset, &alloc_size, &new_code);
00665         RPCStatus rpc_status = dataWrite(db->getDbHandle(), LITERAL_OFFSET,
00666                                          sizeof(char),
00667                                          data, toid.getOid());
00668         
00669         if (rpc_status)
00670           return StatusMake(rpc_status);
00671       }
00672     }
00673 
00674     return Success;
00675   }
00676 
00677   Bool Collection::isLiteralObject() const
00678   {
00679     return is_literal && !is_pure_literal ? True : False;
00680   }
00681 
00682   Status Collection::setLiteralObject(bool reload)
00683   {
00684     if (reload) {
00685       Status s = loadLiteral();
00686       if (s)
00687         return s;
00688     }
00689 
00690     if (!isLiteral())
00691       return Exception::make(IDB_COLLECTION_ERROR,
00692                              "collection %s is not a literal",
00693                              getOid().toString());
00694 
00695 
00696 #if 0
00697     if (isLiteralObject())
00698       return Exception::make(IDB_COLLECTION_ERROR,
00699                              "collection %s is already a literal object",
00700                              getOid().toString());
00701 #endif
00702 
00703     setPureLiteral(False);
00704 
00705     return updateLiteral();
00706   }
00707 
00708   Status Collection::setMasterObject(Object *_master_object)
00709   {
00710     Object *master_obj = 0;
00711     if (is_literal && (master_obj = getMasterObject(true))) {
00712       Object *r_master_object = _master_object->getMasterObject(true);
00713       if (!r_master_object)
00714         r_master_object = _master_object;
00715 
00716       if ((master_obj->getOid().isValid() ||
00717            r_master_object->getOid().isValid()) &&
00718           master_obj->getOid() != r_master_object->getOid()) {
00719         return Exception::make("collection setting master object %s: "
00720                                "%s is already a literal attribute "
00721                                "for the object",
00722                                r_master_object->getOid().toString(),
00723                                getOidC().toString(),
00724                                master_obj->getOid().toString());
00725       }
00726     }
00727 
00728     Status s = Object::setMasterObject(_master_object);
00729     if (s)
00730       return s;
00731 
00732     // must set to pure literal if and only if !getOid().isValid()
00733     // -> eventually patch the Collection data with dataWrite
00734     // at literal_offset
00735     // pure_literal -> char=1
00736     // literal but not pure -> char=2
00737     // not literal and not pure -> char=0
00738     char old_code = codeLiteral();
00739 
00740     setLiteral(True);
00741 
00742     if (getOid().isValid())
00743       setPureLiteral(False); // collection is also an object
00744     else
00745       setPureLiteral(True);
00746 
00747     // EV 26/01/07
00748     // copy oid to literal oid and set oid to null
00749     // in main cases both oids should be invalid
00750     if (!getLiteralOid().isValid())
00751       setLiteralOid(getOid());
00752 
00753     if (!is_pure_literal)
00754       ObjectPeer::setOid(this, Oid::nullOid);
00755 
00756     if (!getDatabase())
00757       setDatabase(_master_object->getDatabase());
00758 
00759     char new_code = codeLiteral();
00760     if (new_code != old_code) {
00761       Status s = updateLiteral();
00762       if (s)
00763         return s;
00764     }
00765 
00766     return Success;
00767   }
00768 
00769   Status
00770   Collection::releaseMasterObject()
00771   {
00772     Status s = loadLiteral();
00773     if (s)
00774       return s;
00775 
00776     bool to_release = (is_pure_literal && getOidC().isValid());
00777     char old_code = codeLiteral();
00778 
00779     setLiteral(False);
00780     setPureLiteral(False);
00781 
00782     char new_code = codeLiteral();
00783 
00784     if (new_code != old_code) {
00785       s = updateLiteral();
00786       if (s)
00787         return s;
00788     }
00789 
00790     // EV 26/01/07
00791     // copy literal oid to oid and set literal oid to null
00792     // in main cases both oids should be invalid
00793 
00794     ObjectPeer::setOid(this, getLiteralOid());
00795     setLiteralOid(Oid::nullOid);
00796 
00797     s = Object::releaseMasterObject();
00798     if (s)
00799       return s;
00800 
00801     if (to_release) {
00802       return remove();
00803     }
00804 
00805     return Success;
00806   }
00807 
00808   //
00809   // Collection check methods
00810   //
00811 
00812   Status Collection::check(const Oid &item_oid,
00813                            const Class *item_class,
00814                            Error err) const
00815   {
00816     Bool is;
00817     Status s = coll_class->isSuperClassOf(item_class, &is);
00818 
00819     if (s)
00820       return s;
00821 
00822     if (is)
00823       return Success;
00824 
00825     return Exception::make(err, "item '%s' is of class '%s', expected subclass of '%s'", item_oid.getString(),
00826                            item_class->getName(),
00827                            coll_class->getName());
00828   }
00829 
00830   Status Collection::check(const Oid& item_oid, Error err) const
00831   {
00832     if (status != Success)
00833       return Exception::make(err,
00834                              "invalid collection status: \"%s\"",
00835                              status->getDesc());
00836     if (!isref)
00837       return Exception::make(err,
00838                              "must use Collection::insert(Data, Size)"
00839                              " or Collection::insert(const Value &)");
00840   
00841     Status s;
00842     Class *item_class;
00843 
00844     s = db->getObjectClass(item_oid, item_class);
00845 
00846     if (s)
00847       return s;
00848 
00849     return check(item_oid, item_class, err);
00850   }
00851 
00852   Status Collection::check(const Object *item_o, Error err) const
00853   {
00854     if (status != Success)
00855       return Exception::make(err,
00856                              "invalid collection status: \"%s\"",
00857                              status->getDesc());
00858 
00859     if (!item_o)
00860       return Exception::make(err, "");
00861 
00862     if (item_o->isOnStack()) {
00863       if (!eyedb_support_stack)
00864         return Exception::make(IDB_COLLECTION_ERROR,
00865                                "cannot insert a stack allocated object in collection '%s'", oid.toString());
00866     }
00867 
00868 
00869     if (!isref &&
00870         !coll_class->asBasicClass() &&
00871         !coll_class->asEnumClass()) {
00872       unsigned int attr_cnt;
00873       const Attribute **attrs = coll_class->getAttributes(attr_cnt);
00874       for (int n = 0; n < attr_cnt; n++) {
00875         const Attribute *attr = attrs[n];
00876         if (!attr->isIndirect())
00877           continue;
00878 
00879         const TypeModifier &tmod = attr->getTypeModifier();
00880         for (int i = 0; i < tmod.pdims; i++) {
00881           Data data_obj = 0;
00882           Status s = attr->getValue(item_o, &data_obj, 1, i);
00883           if (s) 
00884             return s;
00885           if (!data_obj)
00886             continue;
00887           
00888           Oid item_oid;
00889           s = attr->getOid(item_o, &item_oid, 1, i);
00890           if (s) 
00891             return s;
00892           if (!item_oid.isValid())
00893             return Exception::make(IDB_COLLECTION_ERROR,
00894                                    "object is not completed: attribute "
00895                                    "%s::%s has a value and no oid",
00896                                    coll_class->getName(),
00897                                    attr->getName());
00898         }
00899       }
00900     }
00901 
00902     if (isref)
00903       return check(item_o->getOid(), item_o->getClass(), err);
00904 
00905     return Success;
00906   }
00907 
00908   Status Collection::check(Data val, Size size, Error err) const
00909   {
00910     if (status != Success)
00911       return Exception::make(err,
00912                              "invalid collection status: \"%s\"",
00913                              status->getDesc());
00914 
00915     if (isref)
00916       return Exception::make(err, "must use Collection::insert(const Object *) or insert(const Oid&)");
00917       
00918     if (!val)
00919       return Exception::make(err, "trying to insert a null value");
00920 
00921     if (size != defaultSize && size > item_size)
00922       return Exception::make(err, "size too large %d, expected %d", size, item_size);
00923     
00924     return Success;
00925   }
00926 
00927   static const char invalid_type_fmt[] = "invalid type: expected %s, got %s";
00928 
00929   Status Collection::check(const Value &v, Error err) const
00930   {
00931     if (v.type == Value::tObject)
00932       return check(v.o, err);
00933 
00934     if (v.type == Value::tObjectPtr)
00935       return check(v.o_ptr->getObject(), err);
00936 
00937     if (v.type == Value::tOid)
00938       return check(Oid(*v.oid), err);
00939 
00940     if (v.type == Value::tString) {
00941       if (!string_coll)
00942         return Exception::make(err, invalid_type_fmt,
00943                                getStringType().c_str(), v.getStringType());
00944       return check((Data)v.str, strlen(v.str), err);
00945     }
00946 
00947     if (v.type == Value::tChar) {
00948       if (!coll_class->asCharClass())
00949         return Exception::make(err, invalid_type_fmt,
00950                                getStringType().c_str(), v.getStringType());
00951       return check((Data)&v.c, sizeof(v.c), err);
00952     }
00953 
00954     if (v.type == Value::tShort) {
00955       if (!coll_class->asInt16Class())
00956         return Exception::make(err, invalid_type_fmt,
00957                                getStringType().c_str(), v.getStringType());
00958       return check((Data)&v.s, sizeof(v.s), err);
00959     }
00960 
00961     if (v.type == Value::tInt) {
00962       if (!coll_class->asInt32Class())
00963         return Exception::make(err, invalid_type_fmt,
00964                                getStringType().c_str(), v.getStringType());
00965       return check((Data)&v.i, sizeof(v.i), err);
00966     }
00967 
00968     if (v.type == Value::tLong) {
00969       if (!coll_class->asInt64Class())
00970         return Exception::make(err, invalid_type_fmt,
00971                                getStringType().c_str(), v.getStringType());
00972       return check((Data)&v.l, sizeof(v.l), err);
00973     }
00974 
00975     if (v.type == Value::tDouble) {
00976       if (!coll_class->asFloatClass())
00977         return Exception::make(err, invalid_type_fmt,
00978                                getStringType().c_str(), v.getStringType());
00979       return check((Data)&v.d, sizeof(v.d), err);
00980     }
00981 
00982     if (v.type == Value::tData) {
00983       if (!coll_class->asByteClass())
00984         return Exception::make(err, invalid_type_fmt,
00985                                getStringType().c_str(), v.getStringType());
00986       return check(v.data.data, v.data.size, err);
00987     }
00988 
00989     return Exception::make(err, invalid_type_fmt, getStringType().c_str(),
00990                            v.getStringType());
00991   }
00992 
00993   std::string
00994   Collection::getStringType() const
00995   {
00996     string s = coll_class->getName();
00997     if (isref)
00998       s += "*";
00999     if (dim > 1)
01000       s += "[" + str_convert(dim) + "]";
01001     return s;
01002   }
01003 
01004   Status
01005   Collection::insert(const Value &v, Bool noDup)
01006   {
01007     Status s = check(v, IDB_COLLECTION_INSERT_ERROR);
01008     if (s)
01009       return s;
01010 
01011     if (v.type == Value::tObject)
01012       return insert_p(v.o, noDup);
01013 
01014     if (v.type == Value::tObjectPtr)
01015       return insert_p(v.o_ptr->getObject(), noDup);
01016 
01017     if (v.type == Value::tOid)
01018       return insert_p(Oid(*v.oid), noDup);
01019 
01020     Size size;
01021     Data data = v.getData(&size);
01022 
01023     return insert_p(data, noDup, size);
01024   }
01025 
01026   Status
01027   Collection::suppress(const Value &v, Bool checkFirst)
01028   {
01029     Status s = check(v, IDB_COLLECTION_SUPPRESS_ERROR);
01030     if (s)
01031       return s;
01032 
01033     if (v.type == Value::tObject)
01034       return suppress_p(v.o, checkFirst);
01035 
01036     if (v.type == Value::tObjectPtr)
01037       return suppress_p(v.o_ptr->getObject(), checkFirst);
01038 
01039     if (v.type == Value::tOid)
01040       return suppress_p(Oid(*v.oid), checkFirst);
01041 
01042     Size size;
01043     Data data = v.getData(&size);
01044 
01045     return suppress_p(data, checkFirst, size);
01046   }
01047 
01048   //
01049   // Collection suppress methods
01050   //
01051 
01052   Status Collection::suppress_p(const Oid &item_oid, Bool checkFirst)
01053   {
01054     /*
01055       1/ on regarde si oid est present dans la cache: si oui:
01056       si removed    -> error deja detruit
01057       si coherent   -> change le state a` removed; v_items_cnt--;
01058       si added      -> on detruit du cache; v_items_cnt--;
01059 
01060       2/ si oidcoll n'est pas valid -> return error
01061 
01062       3/ on fait:
01063       collectionGetByOid() -> si not found -> error
01064       4/ on insere dans la cache avec le state removed
01065       v_items_cnt--;
01066     */
01067 
01068     if (CollectionPeer::isLocked(this))
01069       return Exception::make(IDB_COLLECTION_LOCKED, "collection '%s' is locked for writing", name);
01070 
01071     if (status)
01072       return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR,
01073                              "invalid collection status: \"%s\"",
01074                              status->getDesc());
01075     /*
01076       printf("Collection::suppress(%s) -> %s\n", item_oid.toString(),
01077       getOid().toString());
01078     */
01079     IDB_COLL_LOAD_DEFERRED();
01080     touch();
01081     ValueItem *item;
01082 
01083     if (cache && (item = cache->get(item_oid)))
01084       {
01085         int s = item->getState();
01086         if (s == removed)
01087           {
01088             if (checkFirst)
01089               return Success;
01090             return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "item '%s' is already suppressed", item_oid.getString());
01091           }
01092         else if (s == coherent)
01093           item->setState(removed);
01094         else if (s == added)
01095           cache->suppressOid(item);
01096 
01097         v_items_cnt--;
01098         return Success;
01099       }
01100 
01101     if (!getOidC().isValid())
01102       return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "collection oid is invalid (collection has not been stored)");
01103 
01104     int found, ind;
01105       
01106     RPCStatus rpc_status;
01107 
01108     if ((rpc_status = collectionGetByOid(db->getDbHandle(),
01109                                              getOidC().getOid(),
01110                                              item_oid.getOid(), &found, &ind)) ==
01111         RPCSuccess)
01112       {
01113         if (!found)
01114           {
01115             if (checkFirst)
01116               return Success;
01117             return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "item '%s' not found in collection '%s'", item_oid.getString(), name);
01118           }
01119       }
01120     else
01121       return StatusMake(IDB_COLLECTION_SUPPRESS_ERROR, rpc_status);
01122 
01123     create_cache();
01124     //cache->insert(item_oid, v_items_cnt, removed);
01125     cache->insert(item_oid, ValueCache::DefaultItemID, removed);
01126     v_items_cnt--;
01127     return Success;
01128   }
01129 
01130   Status Collection::suppress_p(const Object *item_o, Bool checkFirst)
01131   {
01132     /*
01133       1/ on regarde si o est present dans la cache: si oui:
01134       si removed    -> error deja detruit
01135       si coherent   -> change le state a` removed; v_items_cnt--;
01136       si added      -> on detruit du cache; v_items_cnt--;
01137       le state -> removed
01138       return;
01139       2/ si o->getOid() est non valid
01140       return error;
01141 
01142       3/  on regarde si present dans le cache: si oui:
01143       si removed    -> error deja detruit
01144       si coherent   -> change le state a` removed; v_items_cnt--;
01145       si added      -> on detruit du cache; v_items_cnt--;
01146       le state -> removed
01147       return;
01148 
01149       4/ si la collection est realize'e (oid 
01150       valid) on fait:
01151       collectionGetByOid() -> si not found -> return error
01152       5/ on insere dans la cache avec le state removed
01153       v_items_cnt--;
01154     */
01155     if (CollectionPeer::isLocked(this))
01156       return Exception::make(IDB_COLLECTION_LOCKED, "collection '%s' is locked for writing", name);
01157 
01158     if (status != Success)
01159       return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR,
01160                              "invalid collection status: \"%s\"",
01161                              status->getDesc());
01162     if (!item_o)
01163       return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "trying to suppress a null object");
01164 
01165     IDB_COLL_LOAD_DEFERRED();
01166     touch();
01167     ValueItem *item;
01168 
01169     if (cache && (item = cache->get(item_o)))
01170       {
01171         int s = item->getState();
01172         if (s == removed)
01173           {
01174             if (checkFirst)
01175               return Success;
01176             return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "object 0x%x has already been suppressed", item_o);
01177           }
01178         else if (s == coherent)
01179           item->setState(removed);
01180         else if (s == added)
01181           cache->suppressObject(item);
01182 
01183         v_items_cnt--;
01184         return Success;
01185       }
01186 
01187     Oid item_oid = item_o->getOid();
01188 
01189     if (!item_oid.isValid())
01190       return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "oid item of object 0x%x is invalid", item_o);
01191 
01192     if (cache && (item = cache->get(item_oid)))
01193       {
01194         int s = item->getState();
01195         if (s == removed)
01196           {
01197             if (checkFirst)
01198               return Success;
01199             return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "item '%s' has been already suppressed", item_oid.getString());
01200           }
01201         else if (s == coherent)
01202           item->setState(removed);
01203         else if (s == added)
01204           item->setState(removed); /* cache->suppress(item); */
01205 
01206         v_items_cnt--;
01207         return Success;
01208       }
01209 
01210     if (!getOidC().isValid())
01211       return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "collection oid is invalid (collection has not been stored)");
01212 
01213     int found, ind;
01214       
01215     RPCStatus rpc_status;
01216 
01217     if ((rpc_status = collectionGetByOid(db->getDbHandle(),
01218                                              getOidC().getOid(),
01219                                              item_oid.getOid(), &found, &ind)) ==
01220         RPCSuccess)
01221       {
01222         if (!found)
01223           {
01224             if (checkFirst)
01225               return Success;
01226             return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR, "item '%s' not found in collection", item_oid.toString());
01227           }
01228       }
01229     else
01230       return StatusMake(IDB_COLLECTION_SUPPRESS_ERROR, rpc_status);
01231 
01232     create_cache();
01233     //cache->insert(item_o, v_items_cnt, removed);
01234     cache->insert(item_o, ValueCache::DefaultItemID, removed);
01235     v_items_cnt--;
01236     return Success;
01237   }
01238 
01239   Status Collection::suppress_p(Data val, Bool, Size size)
01240   {
01241     if (status != Success)
01242       return Exception::make(IDB_COLLECTION_SUPPRESS_ERROR,
01243                              "invalid collection status: \"%s\"",
01244                              status->getDesc());
01245     return Exception::make(IDB_ERROR, "Collection::suppress(Data val) is not implemented");
01246   }
01247 
01248   //
01249   // Collection empty method
01250   //
01251 
01252   Status Collection::empty()
01253   {
01254     if (CollectionPeer::isLocked(this))
01255       return Exception::make(IDB_COLLECTION_LOCKED,
01256                              "collection '%s' is locked for writing", name);
01257 
01258     emptyReadCache();
01259 
01260     if (cache) {
01261       cache->setState(removed);
01262     }
01263 
01264     IDB_COLL_LOAD_DEFERRED();
01265     touch();
01266     if (!getOidC().isValid())
01267       {
01268         p_items_cnt = 0;
01269         v_items_cnt = 0;
01270         top = bottom = 0;
01271         return Success;
01272       }
01273 
01274     Status s;
01275     Iterator q(this, True);
01276 
01277     if ((s = q.getStatus()))
01278       return s;
01279 
01280     IteratorAtom qatom;
01281     int ind = 0;
01282     for (int n = 0; ; n++) {
01283       Bool found;
01284       s = q.scanNext(&found, &qatom);
01285       if (s) {
01286         //cache->empty();
01287         return s;
01288       }
01289 
01290       if (!found)
01291         break;
01292       
01293       if (asCollArray()) {
01294         if (!(n & 1)) {
01295           assert(qatom.type == IteratorAtom_INT32);
01296           ind = qatom.i32;
01297           continue;
01298         }
01299       }
01300       else
01301         ind = ValueCache::DefaultItemID;
01302 
01303       create_cache();
01304       if (isref)
01305         cache->insert(&qatom.oid, ind, removed);
01306       else {
01307         Data _idr = 0;
01308         Offset offset = 0;
01309         Size alloc_size = 0;
01310         qatom.code(&_idr, &offset, &alloc_size);
01311         cache->insert(Value(idr->getIDR(), item_size), ind, removed);
01312       }
01313     }
01314 
01315     p_items_cnt = 0;
01316     v_items_cnt = 0;
01317     top = bottom = 0;
01318     return Success;
01319   }
01320 
01321   //
01322   // Collection isIn methods
01323   //
01324 
01325   Status Collection::isIn_p(const Oid &item_oid, Bool &found,
01326                             Collection::ItemId *where) const
01327   {
01328     /*
01329       1/ on regarde si _oid est present dans la cache: si oui -> si le
01330       state est non removed return true 
01331       2/ si oidcoll est :
01332       collectionGetByOid() -> true ou false
01333     */
01334     //  printf("Collection::isIn(%s)\n", item_oid.getString());
01335     ValueItem *item;
01336 
01337     found = False;
01338 
01339     if (cache && (item = cache->get(item_oid))) {
01340       if (item->getState() != removed)
01341         found = True;
01342 
01343       return Success;
01344     }
01345       
01346     if (!getOidC().isValid())
01347       return Success;
01348 
01349     //  printf("Collection::isIn_p #1\n");
01350     int f, ind;
01351       
01352     RPCStatus rpc_status;
01353 
01354     rpc_status = collectionGetByOid(db->getDbHandle(), getOidC().getOid(),
01355                                         item_oid.getOid(), &f, &ind);
01356     //  printf("Collection::isIn_p #2 -> %d\n", f);
01357     found = (f ? True : False);
01358     if (found && where) *where = ind;
01359 
01360     return StatusMake(IDB_COLLECTION_IS_IN_ERROR, rpc_status);
01361   }
01362 
01363   Status Collection::isIn_p(const Object *item_o, Bool &found,
01364                             Collection::ItemId *where) const
01365   {
01366     /*
01367       1/ on regarde si _o est present dans la cache: si oui return true
01368       2/ si o->getOid() est valid ET si la collection est realize'e (oid 
01369       valid) on fait:
01370       collectionGetByOid() -> true ou false
01371     */
01372     found = False;
01373 
01374     if (!item_o)
01375       return Exception::make(IDB_COLLECTION_IS_IN_ERROR, "trying to check presence of a null object");
01376 
01377     if (!isref)
01378       return isIn_p(item_o->getIDR() + IDB_OBJ_HEAD_SIZE, found, defaultSize,
01379                     where);
01380 
01381     ValueItem *item;
01382 
01383     if (cache && (item = cache->get(item_o)) && item->getState() != removed)
01384       {
01385         found = True;
01386         return Success;
01387       }
01388       
01389     Oid item_oid = item_o->getOid();
01390 
01391     if (item_oid.isValid() && cache && (item = cache->get(item_oid)) &&
01392         item->getState() != removed)
01393       {
01394         found = True;
01395         return Success;
01396       }
01397 
01398     if (!getOidC().isValid())
01399       return Success;
01400 
01401     int f, ind;
01402       
01403     RPCStatus rpc_status;
01404 
01405     rpc_status = collectionGetByOid(db->getDbHandle(), getOidC().getOid(),
01406                                         item_oid.getOid(), &f, &ind);
01407 
01408     found = (f ? True : False);
01409     if (found && where) *where = ind;
01410     return StatusMake(IDB_COLLECTION_IS_IN_ERROR, rpc_status);
01411   }
01412 
01413   Status Collection::isIn_p(Data data, Bool &found, Size size,
01414                             Collection::ItemId *where) const
01415   {
01416     /*
01417       1/ on regarde si _o est present dans la cache: si oui return true
01418       2/ si la collection est realize'e (oid valid) on fait:
01419       collectionGetByValue() -> true ou false
01420     */
01421     ((Collection *)this)->status = check(data, size, IDB_COLLECTION_IS_IN_ERROR);
01422 
01423     if (status != Success)
01424       return status;
01425 
01426     ValueItem *item;
01427 
01428     Data item_data = make_data(data, size, True);
01429 
01430     if (!item_data)
01431       return Exception::make(IDB_COLLECTION_ERROR, "data too long for collection search");
01432 
01433     if (cache && (item = cache->get(item_data, item_size))) {
01434       if (item->getState() != removed)
01435         found = True;
01436       return Success;
01437     }
01438       
01439     if (!getOidC().isValid())
01440       return Success;
01441 
01442     int f, ind;
01443       
01444     RPCStatus rpc_status;
01445 
01446     rpc_status = collectionGetByValue(db->getDbHandle(),
01447                                           getOidC().getOid(), item_data,
01448                                           item_size, &f, &ind);
01449 
01450     found = (f ? True : False);
01451     if (found && where) *where = ind;
01452     return StatusMake(IDB_COLLECTION_IS_IN_ERROR, rpc_status);
01453   }
01454 
01455   Status Collection::isIn(const Value &v, Bool &found,
01456                           Collection::ItemId *where) const
01457   {
01458     Status s = check(v, IDB_COLLECTION_ERROR);
01459     if (s)
01460       return s;
01461 
01462     if (v.type == Value::tObject)
01463       return isIn_p(v.o, found, where);
01464 
01465     if (v.type == Value::tObjectPtr)
01466       return isIn_p(v.o_ptr->getObject(), found, where);
01467 
01468     if (v.type == Value::tOid)
01469       return isIn_p(Oid(*v.oid), found, where);
01470 
01471     Size size;
01472     Data data = v.getData(&size);
01473 
01474     return isIn_p(data, found, size, where);
01475   }
01476 
01477   Status Collection::getStatus() const
01478   {
01479     return status;
01480   }
01481 
01482   int Collection::getCount() const
01483   {
01484     if (!is_complete)
01485       (void)const_cast<Collection *>(this)->loadDeferred();
01486     return v_items_cnt;
01487   }
01488 
01489   int
01490   Collection::getBottom() const
01491   {
01492     if (!is_complete)
01493       (void)const_cast<Collection *>(this)->loadDeferred();
01494     return bottom;
01495   }
01496 
01497   int
01498   Collection::getTop() const
01499   {
01500     if (!is_complete)
01501       (void)const_cast<Collection *>(this)->loadDeferred();
01502     return top;
01503   }
01504 
01505   Bool Collection::isEmpty() const
01506   {
01507     if (!is_complete)
01508       (void)const_cast<Collection *>(this)->loadDeferred();
01509     return (v_items_cnt == 0 ? True : False);
01510   }
01511 
01512   void Collection::setName(const char *_name)
01513   {
01514     if (!is_complete)
01515       (void)const_cast<Collection *>(this)->loadDeferred();
01516     free(name);
01517     name = strdup(_name);
01518   }
01519 
01520   void Collection::garbage()
01521   {
01522     free(name);
01523     delete cache;
01524     emptyReadCache();
01525     free(idx_data);
01526     Instance::garbage();
01527     if (idximpl)
01528       idximpl->release();
01529   }
01530 
01531   Collection::~Collection()
01532   {
01533     garbageRealize();
01534   }
01535 
01536   Status Collection::setValue(Data)
01537   {
01538     return Success;
01539   }
01540 
01541   Status Collection::getValue(Data*) const
01542   {
01543     return Success;
01544   }
01545 
01546   Status Collection::create()
01547   {
01548     return create_realize(NoRecurs);
01549   }
01550 
01551   void
01552   Collection::cardCode(Data &data, Offset &offset, Size &alloc_size)
01553   {
01554     //  printf("collection_realize(card_code = %s)\n", card_oid.toString());
01555     if (card_oid.isValid())
01556       {
01557         oid_code(&data, &offset, &alloc_size, card_oid.getOid());
01558         return;
01559       }
01560 
01561     oid_code(&data, &offset, &alloc_size, getInvalidOid());
01562   }
01563 
01564   Object *
01565   Collection::cardDecode(Database *db, Data temp, Offset &offset)
01566   {
01567     eyedbsm::Oid xoid;
01568 
01569     oid_decode(temp, &offset, &xoid);
01570 
01571     Oid coid(xoid);
01572 
01573     //  printf("collection_make(card_decode = %s)\n", coid.toString());
01574 
01575     if (!coid.isValid())
01576       return NULL;
01577 
01578     Object *card;
01579 
01580     Status status = db->loadObject(&coid, &card);
01581 
01582     if (status)
01583       {
01584         status->print();
01585         return NULL;
01586       }
01587 
01588     return card;
01589   }
01590 
01591   Status
01592   Collection::codeIndexImpl(Data &data, Offset &offset,
01593                             Size &alloc_size)
01594   {
01595     return IndexImpl::code(data, offset, alloc_size, *idximpl);
01596   }
01597 
01598   Status
01599   Collection::getImplStats(std::string &xstats, Bool dspImpl, Bool full,
01600                            const char *indent)
01601   {
01602     IndexStats *stats;
01603     Status s = getImplStats(stats);
01604     if (s) return s;
01605     xstats = (stats ? stats->toString(dspImpl, full, indent) : std::string(""));
01606     delete stats;
01607     return Success;
01608   }
01609 
01610   void
01611   Collection::completeImplStats(IndexStats *stats) const
01612   {
01613     if (idximpl->getDataspace())
01614       stats->idximpl->setDataspace(idximpl->getDataspace());
01615     if (idximpl->getHashMethod())
01616       stats->idximpl->setHashMethod(idximpl->getHashMethod());
01617   }
01618 
01619   Status
01620   Collection::getIdxOid(Oid &idx1oid, Oid &idx2oid) const
01621   {
01622     idx1oid = idx1_oid;
01623     idx2oid = idx2_oid;
01624 
01625     if (is_literal && !idx1oid.isValid()) {
01626       if (literal_oid.isValid()) {
01627         Object *o;
01628         Status s = db->loadObject(literal_oid, (Object *&)o);
01629         if (s) return s;
01630         idx1oid = o->asCollection()->idx1_oid;
01631         idx2oid = o->asCollection()->idx2_oid;
01632         o->release();
01633       }
01634     }
01635 
01636     return Success;
01637   }
01638 
01639   Status
01640   Collection::getImplStats(IndexStats *&stats)
01641   {
01642     Oid idx1oid, idx2oid;
01643     Status s = getIdxOid(idx1oid, idx2oid);
01644     if (s) return s;
01645 
01646     if (idx1oid.isValid()) {
01647       RPCStatus rpc_status =
01648         collectionGetImplStats(db->getDbHandle(), idximpl->getType(),
01649                                    idx1oid.getOid(), (Data *)&stats);
01650       if (rpc_status)
01651         return StatusMake(rpc_status);
01652       completeImplStats(stats);
01653       return Success;
01654     }
01655 
01656     stats = 0;
01657     return Success;
01658   }
01659 
01660   Status
01661   Collection::simulate(const IndexImpl &_idximpl, std::string &xstats,
01662                        Bool dspImpl, Bool full, const char *indent)
01663   {
01664     IndexStats *stats;
01665     Status s = simulate(_idximpl, stats);
01666     if (s) return s;
01667     xstats = (stats ? stats->toString(dspImpl, full, indent) : std::string(""));
01668     delete stats;
01669     return Success;
01670   }
01671 
01672   Status
01673   Collection::simulate(const IndexImpl &_idximpl, IndexStats *&stats)
01674   {
01675     Oid idx1oid, idx2oid;
01676     Status s = getIdxOid(idx1oid, idx2oid);
01677     if (s) return s;
01678 
01679     if (idx1oid.isValid()) {
01680       Data data;
01681       Offset offset = 0;
01682       Size size = 0;
01683       Status s = IndexImpl::code(data, offset, size, _idximpl);
01684       if (s) return s;
01685       RPCStatus rpc_status =
01686         collectionSimulImplStats(db->getDbHandle(), _idximpl.getType(),
01687                                      idx1oid.getOid(), data, size,
01688                                      (Data *)&stats);
01689       return StatusMake(rpc_status);
01690     }
01691 
01692     stats = 0;
01693     return Success;
01694   }
01695 
01696   Status Collection::init_idr() {
01697 #ifdef INIT_IDR
01698     assert(!getIDR());
01699     Size alloc_size = 0;
01700     Offset offset = IDB_OBJ_HEAD_SIZE;
01701 
01702     idr->setIDR((Size)0);
01703     Data data = 0;
01704 
01705     /* locked */
01706     char c = locked;
01707     char_code (&data, &offset, &alloc_size, &c);
01708 
01709     /* item_size */
01710     eyedblib::int16 kk = (eyedblib::int16)item_size;
01711     int16_code (&data, &offset, &alloc_size, &kk);
01712 
01713     Status s = codeIndexImpl(data, offset, alloc_size);
01714     if (s)
01715       return s;
01716 
01717     /* null oid */
01718     oid_code (&data, &offset, &alloc_size, getInvalidOid());
01719     /* null oid */
01720     oid_code (&data, &offset, &alloc_size, getInvalidOid());
01721 
01722     eyedblib::int32 zero = 0;
01723     /* item count */
01724 
01725     int32_code (&data, &offset, &alloc_size, &zero);
01726     /* bottom */
01727     int32_code (&data, &offset, &alloc_size, &zero);
01728     /* top */
01729     int32_code (&data, &offset, &alloc_size, &zero);
01730   
01731     cardCode(data, offset, alloc_size);
01732 
01733     inv_oid_offset = offset;
01734     oid_code(&data, &offset, &alloc_size, inv_oid.getOid());
01735     int16_code(&data, &offset, &alloc_size, &inv_item);
01736 
01737     char c = codeLiteral();
01738     /* is_literal */
01739     LITERAL_OFFSET = offset;
01740     char_code (&data, &offset, &alloc_size, &c);
01741     eyedblib::int16 sz = idx_data_size;
01742     int16_code (&data, &offset, &alloc_size, &sz);
01743     buffer_code(&data, &offset, &alloc_size, idx_data, idx_data_size);
01744 
01745     /* collection name */
01746     string_code(&data, &offset, &alloc_size, name);
01747 
01748     int idr_sz = offset;
01749     idr->setIDR(idr_sz, data);
01750     headerCode(type, idr_sz);
01751 #endif
01752     return Success;
01753   }
01754 
01755   Status Collection::create_realize(const RecMode *rcm)
01756   {
01757     if (status != Success)
01758       return Exception::make(IDB_COLLECTION_ERROR,
01759                              "invalid collection status: \"%s\"",
01760                              status->getDesc());
01761 
01762     if (getOidC().isValid())
01763       return Exception::make(IDB_OBJECT_ALREADY_CREATED, "%scollection %s",
01764                              is_literal ? "literal " : "",
01765                              getOidC().toString());
01766 
01767     IDB_CHECK_WRITE(db);
01768   
01769     Status s;
01770     if (!getClass()->getOid().isValid()) {
01771       s = getClass()->create();
01772       if (s) return s;
01773     }
01774 
01775 #if 0
01776     Size wr_size = 0;
01777     unsigned char *temp = 0;
01778     Offset cache_offset = 0;
01779     if (!is_literal) {
01780       s = cache_compile(cache_offset, wr_size, &temp, rcm);
01781       if (s) return s;
01782     }
01783 #endif
01784 
01785 #ifdef INIT_IDR
01786     assert(getIDR());
01787     //init_idr();
01788 #else
01789     Size alloc_size = 0;
01790     Offset offset = IDB_OBJ_HEAD_SIZE;
01791 
01792     idr->setIDR((Size)0);
01793     Data data = 0;
01794 
01795     /* locked */
01796     char c = locked;
01797     char_code (&data, &offset, &alloc_size, &c);
01798 
01799     /* item_size */
01800     eyedblib::int16 kk = (eyedblib::int16)item_size;
01801     int16_code (&data, &offset, &alloc_size, &kk);
01802 
01803     s = codeIndexImpl(data, offset, alloc_size);
01804     if (s) return s;
01805 
01806     /* null oid */
01807     oid_code (&data, &offset, &alloc_size, getInvalidOid());
01808     /* null oid */
01809     oid_code (&data, &offset, &alloc_size, getInvalidOid());
01810 
01811     eyedblib::int32 zero = 0;
01812     /* item count */
01813 
01814     int32_code (&data, &offset, &alloc_size, &zero);
01815     /* bottom */
01816     int32_code (&data, &offset, &alloc_size, &zero);
01817     /* top */
01818     int32_code (&data, &offset, &alloc_size, &zero);
01819   
01820     cardCode(data, offset, alloc_size);
01821 #endif
01822 
01823     if (is_literal) {
01824 #ifdef NEW_MASTER_OBJ
01825       Object *o = getMasterObject(true);
01826 #else
01827       Object *o = get_master_object(getMasterObject());
01828 #endif
01829       if (!inv_oid.isValid())
01830         inv_oid = o->getOid();
01831 
01832       if (!o->getOid().isValid())
01833         return Exception::make(IDB_ERROR,
01834                                "inner object of class '%s' containing "
01835                                "collection of type '%s' has no valid oid",
01836                                o->getClass()->getName(), getClass()->getName());
01837 
01838       assert(inv_oid == o->getOid());
01839     }
01840 
01841 #ifdef INIT_IDR
01842     Offset offset = inv_oid_offset;
01843     assert(offset);
01844     Size alloc_size = idr->getSize();
01845     Data data = idr->getIDR();
01846 
01847     oid_code(&data, &offset, &alloc_size, inv_oid.getOid());
01848 
01849     int16_code(&data, &offset, &alloc_size, &inv_item);
01850 
01851     c = codeLiteral();
01852     /* is_literal */
01853     char_code (&data, &offset, &alloc_size, &c);
01854     eyedblib::int16 sz = idx_data_size;
01855     printf("IDX_DATA_SIZE = %d\n", idx_data_size);
01856     int16_code (&data, &offset, &alloc_size, &sz);
01857     buffer_code(&data, &offset, &alloc_size, idx_data, idx_data_size);
01858 #else
01859     //printf("inv_oid_offset %d idx_data_size %d name %d ", offset, idx_data_size,  strlen(name));
01860     oid_code(&data, &offset, &alloc_size, inv_oid.getOid());
01861 
01862     int16_code(&data, &offset, &alloc_size, &inv_item);
01863 
01864     c = codeLiteral();
01865     /* is_literal */
01866     char_code (&data, &offset, &alloc_size, &c);
01867     eyedblib::int16 sz = idx_data_size;
01868     int16_code (&data, &offset, &alloc_size, &sz);
01869     buffer_code(&data, &offset, &alloc_size, idx_data, idx_data_size);
01870 
01871     /* collection name */
01872     string_code(&data, &offset, &alloc_size, name);
01873 
01874     int idr_sz = offset;
01875     idr->setIDR(idr_sz, data);
01876     headerCode(type, idr_sz);
01877     //printf("IDR size %d\n", idr_sz);
01878     // -------------- end of IDR creation
01879 #endif
01880 
01881     // -------------- begin of object creation
01882     RPCStatus rpc_status;
01883     //printf("collection create %s %s %d\n", getClass()->getName(), getClass()->getOid().toString(), getDataspaceID());
01884     rpc_status = objectCreate(db->getDbHandle(), getDataspaceID(), data, getOidC().getOid());
01885 
01886     if (rpc_status != RPCSuccess)
01887       return StatusMake(IDB_COLLECTION_ERROR, rpc_status);
01888 
01889     if (!getOidC().getDbid() && getOidC().getNX())
01890       abort();
01891 
01892     db->cacheObject(this); // added the 30/08/99
01893 
01894     if (is_literal) {
01895       implModified = False;
01896       return Success;
01897     }
01898 
01899     // -------------- end of object creation
01900 
01901     ObjectHeader hdr;
01902     memset(&hdr, 0, sizeof(hdr));
01903   
01904 #if 1
01905     Size wr_size = 0;
01906     unsigned char *temp = 0;
01907     Offset cache_offset = 0;
01908     if (!is_literal) {
01909       s = cache_compile(cache_offset, wr_size, &temp, rcm);
01910       if (s) return s;
01911     }
01912 #endif
01913 
01914     if (wr_size) {
01915       short x = IDB_COLL_IMPL_UNCHANGED;
01916       int16_code(&temp, &cache_offset, &wr_size, &x);
01917 
01918       hdr.type = type;
01919       hdr.size = wr_size;
01920   
01921       object_header_code_head(temp, &hdr);
01922   
01923       rpc_status = objectWrite(db->getDbHandle(), temp, getOidC().getOid());
01924     }
01925   
01926     free(temp);
01927     if (!rpc_status) {
01928       delete cache;
01929       cache = 0;
01930       emptyReadCache();
01931       implModified = False;
01932       modify = False;
01933     }
01934 
01935     return StatusMake(IDB_COLLECTION_ERROR, rpc_status);
01936   }
01937 
01938   Status Collection::update()
01939   {
01940     return update_realize(NoRecurs);
01941   }
01942 
01943   Status Collection::update_realize(const RecMode *rcm)
01944   {
01945     if (status != Success)
01946       return Exception::make(IDB_COLLECTION_ERROR,
01947                              "invalid collection status: \"%s\"",
01948                              status->getDesc());
01949 
01950     if (!getOidC().isValid())
01951       return Exception::make(IDB_COLLECTION_ERROR, "collection oid '%s' is not valid", name);
01952 
01953     if (!getClass()->getOid().isValid())
01954       return Exception::make(IDB_COLLECTION_ERROR, "collection '%s' has not a valid class", name);
01955 
01956     //printf("Collection::update_realize(%s)\n", getOidC().toString());
01957     Size alloc_size;
01958 
01959     unsigned char *temp;
01960     Offset offset;
01961     Status _status = cache_compile(offset, alloc_size, &temp, rcm);
01962     if (_status)
01963       return _status;
01964 
01965     RPCStatus rpc_status;
01966 
01967     ObjectHeader hdr;
01968     memset(&hdr, 0, sizeof(hdr));
01969 
01970     short c = (implModified ? IDB_COLL_IMPL_CHANGED : IDB_COLL_IMPL_UNCHANGED);
01971     int16_code(&temp, &offset, &alloc_size, &c);
01972     if (implModified) {
01973       _status = IndexImpl::code(temp, offset, alloc_size, *idximpl);
01974       if (_status)
01975         return _status;
01976     }
01977 
01978     hdr.type = type;
01979     hdr.size = alloc_size;
01980     hdr.xinfo = (!inverse_valid ? IDB_XINFO_INVALID_INV : 0);
01981 
01982     object_header_code_head(temp, &hdr);
01983 
01984     rpc_status = objectWrite(db->getDbHandle(), temp, getOidC().getOid());
01985     free(temp);
01986     if (!rpc_status) {
01987       delete cache;
01988       cache = 0;
01989       emptyReadCache();
01990       modify = False;
01991       implModified = False;
01992     }
01993 
01994     return StatusMake(IDB_COLLECTION_ERROR, rpc_status);
01995   }
01996 
01997 #define IDB_MAGIC_COLL  ((void *)0x2e372811)
01998 #define IDB_MAGIC_COLL2 ((void *)0xe3728113)
01999 
02000   Status Collection::realize(const RecMode *rcm)
02001   {
02002     if (state & Realizing)
02003       return Success;
02004 
02005     CHK_OBJ(this);
02006 
02007 #ifdef COLLTRACE
02008     printf("realizing %p %s %d\n", this, getOidC().toString(),
02009            CACHE_LIST_COUNT(cache));
02010 #endif
02011 
02012 #ifdef COLL_OPTIM_CREATE
02013     if (is_literal && !CACHE_LIST_COUNT(cache) && !implModified) {
02014       //if (!getCount() || literal_oid.isValid())
02015         return Success;
02016     }
02017 #endif
02018 
02019     if (is_literal && !literal_oid.isValid() && getUserData() != IDB_MAGIC_COLL)
02020       {
02021 #ifdef COLLTRACE
02022         printf("collection realizing master_object %p\n",
02023                getMasterObject(true));
02024 #endif
02025         assert(getMasterObject(true));
02026         void *ud = setUserData(IDB_MAGIC_COLL2);
02027         Status s = getMasterObject(true)->realize(rcm);
02028         (void)setUserData(ud);
02029         return s;
02030       }
02031 
02032     Status s;
02033     IDB_COLL_LOAD_DEFERRED();
02034     state |= Realizing;
02035 
02036     if (!getOidC().isValid())
02037       s = create_realize(rcm);
02038     else if (modify || collupd_noopt)
02039       s = update_realize(rcm);
02040     else
02041       s = Success;
02042 
02043     state &= ~Realizing;
02044     return s;
02045   }
02046 
02047   Status Collection::remove(const RecMode *rcm)
02048   {
02049     Status s;
02050 
02051 #ifdef COLLTRACE
02052     printf("removing collection %s\n", getOidC().toString());
02053 #endif
02054 
02055     s = loadLiteral();
02056     if (s)
02057       return s;
02058 
02059     if (is_literal)
02060       return Exception::make("collection %s is a literal object: could not be removed", getOid().toString());
02061 
02062     s = Object::remove();
02063 
02064     if (!s) {
02065       delete cache;
02066       cache = 0;
02067       p_items_cnt = v_items_cnt = 0;
02068     }
02069 
02070     return s;
02071   }
02072 
02073   Status Collection::trace(FILE* fd, unsigned int flags, const RecMode *rcm) const
02074   {
02075     fprintf(fd, "%s %s = ", oid.getString(), getClass()->getName());
02076     return trace_realize(fd, INDENT_INC, flags, rcm);
02077   }
02078 
02079   Status Collection::trace_contents_realize(FILE* fd, int indent, unsigned int flags, const RecMode *rcm) const
02080   {
02081     // To get contents, make a query on 
02082     char *indent_str = make_indent(indent);
02083     ValueArray array;
02084     Bool isidx = (asCollArray() || asCollList()) ? True : False;
02085 
02086     Status s = getElements(array, (isidx ? True : False));
02087 
02088     if (s)
02089       return s;
02090 
02091     int inc = (isidx ? 2 : 1);
02092     int value_off = (isidx ? 1 : 0);
02093     int ind;
02094 
02095     unsigned int cnt = array.getCount();
02096     for (int i = 0; i < cnt; i += inc)
02097       {
02098         IDB_CHECK_INTR();
02099         Value value = array[i+value_off]; //Value value = array.values[i+value_off];
02100 
02101         if (isidx)
02102           ind = array[i].l; // ind = array.values[i].l;
02103 
02104         if (value.type == Value::tOid)
02105           {
02106             Object *o;
02107             s = db->loadObject(value.oid, &o, rcm);
02108             if (s)
02109               {
02110                 delete_indent(indent_str);
02111                 return s;
02112               }
02113 
02114             if (isidx)
02115               fprintf(fd, "%s[%d] = %s %s ", indent_str, ind,
02116                       value.oid->getString(), o->getClass()->getName());
02117             else
02118               fprintf(fd, "%s%s %s = ", indent_str, value.oid->getString(),
02119                       o->getClass()->getName());
02120             s = ObjectPeer::trace_realize(o, fd, indent + INDENT_INC, flags, rcm);
02121             if (s)
02122               {
02123                 delete_indent(indent_str);
02124                 return s;
02125               }
02126 
02127             o->release();
02128           }
02129         else if (isidx)
02130           fprintf(fd, "%s[%d] = %s;\n", indent_str, ind, value.getString());
02131         else
02132           fprintf(fd, "%s%s;\n", indent_str, value.getString());
02133       }
02134 
02135     delete_indent(indent_str);
02136     return Success;
02137   }
02138 
02139   Status Collection::trace_realize(FILE* fd, int indent, unsigned int flags, const RecMode *rcm) const
02140   {
02141     IDB_CHECK_INTR();
02142 
02143     // IDB_COLL_LOAD_DEFERRED();
02144     Status s = Success;
02145     char *indent_str = make_indent(indent);
02146 
02147     if (state & Tracing)
02148       {
02149         fprintf(fd, "%s%s;\n", indent_str, oid.getString());
02150         delete_indent(indent_str);
02151         return Success;
02152       }
02153 
02154     if (!is_complete)
02155       {
02156         s = const_cast<Collection *>(this)->loadDeferred();
02157         if (s) return s;
02158       }
02159 
02160     const_cast<Collection *>(this)->state |= Tracing;
02161 
02162     char *lastindent_str = make_indent(indent - INDENT_INC);
02163 
02164     fprintf(fd, "%s { ", getClassName());
02165     if (traceRemoved(fd, indent_str))
02166       goto out;
02167     trace_flags(fd, flags);
02168     fprintf(fd, "\n");
02169 
02170     if ((flags & NativeTrace) == NativeTrace)
02171       {
02172         if (rcm->getType() == RecMode_FullRecurs)
02173           {
02174             fprintf(fd, "%s%s class = { ", indent_str,
02175                     getClass()->getOid().getString());
02176           
02177             if (s = ObjectPeer::trace_realize(getClass(), fd, indent + INDENT_INC, flags, rcm))
02178               goto out;
02179 
02180             fprintf(fd, "%s};\n", indent_str);
02181 
02182             fprintf(fd, "%s%s collclass = { ", indent_str,
02183                     coll_class->getOid().getString());
02184 
02185             if (s = ObjectPeer::trace_realize(coll_class, fd, indent + INDENT_INC, flags, rcm))
02186               goto out;
02187 
02188             fprintf(fd, "%s};\n", indent_str);
02189           }
02190         else
02191           {
02192             fprintf(fd, "%sclass = %s;\n", indent_str,
02193                     getClass()->getOid().getString());
02194   
02195             fprintf(fd, "%scollclass = %s;\n", indent_str,
02196                     coll_class->getOid().getString());
02197 
02198             fprintf(fd, "%sreference = %s;\n", indent_str, (isref ? "true" : "false"));
02199             if (isPureLiteral())
02200               fprintf(fd, "%stype = pure_literal;\n", indent_str);
02201             else if (isLiteral())
02202               fprintf(fd, "%stype = object_literal;\n", indent_str);
02203             else
02204               fprintf(fd, "%stype = object;\n", indent_str);
02205 
02206             if (isLiteral())
02207               fprintf(fd, "%sliteral_oid = %s;\n", indent_str, getOidC().toString());
02208 
02209             fprintf(fd, "%sidxtype = '%s';\n", indent_str,
02210                     idximpl->getType() == IndexImpl::BTree ?
02211                     "BTree" : "Hash");
02212 
02213             std::string hints = idximpl->getHintsString();
02214             if (hints.size())
02215               fprintf(fd, "%shints = \"%s\";\n", indent_str,
02216                       hints.c_str());
02217 
02218             if (idx1_oid.isValid())
02219               fprintf(fd, "%sidx1oid = %s;\n", indent_str,
02220                       idx1_oid.toString());
02221             if (idx2_oid.isValid())
02222               fprintf(fd, "%sidx2oid = %s;\n", indent_str,
02223                       idx2_oid.toString());
02224           }
02225       }
02226 
02227     fprintf(fd, "%sname = \"%s\";\n", indent_str, name);
02228     fprintf(fd, "%scount = %d;\n", indent_str, v_items_cnt);
02229 
02230     if (asCollArray())
02231       fprintf(fd, "%srange = [%d,%d[;\n", indent_str, bottom, top);
02232 
02233     if (card)
02234       fprintf(fd, "%sconstraint = (%s);\n", indent_str, card->getString());
02235 
02236     if (flags & ContentsFlag)
02237       {
02238         fprintf(fd, "%scontents = {\n", indent_str);
02239         s = trace_contents_realize(fd, indent + INDENT_INC, flags, rcm);
02240         fprintf(fd, "%s};\n", indent_str);
02241       }
02242 
02243   out:
02244     const_cast<Collection *>(this)->state &= ~Tracing;
02245     fprintf(fd, "%s};\n", lastindent_str);
02246     delete_indent(indent_str);
02247     delete_indent(lastindent_str);
02248 
02249     return s;
02250   }
02251 
02252   //
02253   // MIND: these methods are not good, because they do not take the
02254   // collection cache into account.
02255   //
02256   // for instance:
02257   // Collection *coll;
02258   // coll->insert(oid1);
02259   // coll->insert(oid2);
02260   //
02261   // coll->getElements(oid_array);
02262   // 
02263   // oid_array will contains only the oids in database and not oid1 and
02264   // oid2.
02265   //
02266   // Another pb is the coherency between getCount() (v_items_cnt) and
02267   // the actual item count in the database.
02268   //
02269 
02270   Status Collection::getElements(OidArray &oid_array) const
02271   {
02272     if (status)
02273       return Exception::make(status);
02274 
02275     Status s =  const_cast<Collection *>(this)->getOidElementsRealize();
02276     if (s) return s;
02277 
02278     oid_array = *read_cache.oid_arr;
02279     return Success;
02280   }
02281 
02282   Status Collection::getOidElementsRealize()
02283   {
02284     if (!isref)
02285       return Exception::make(IDB_COLLECTION_ERROR,
02286                              "cannot get oid elements");
02287 
02288     IDB_COLL_LOAD_DEFERRED();
02289 
02290     if (read_cache.oid_arr && read_cache_state_oid == coherent)
02291       return Success;
02292 
02293     delete read_cache.oid_arr;
02294     read_cache.oid_arr = new OidArray();
02295     if (getOidC().isValid())
02296       {
02297         Iterator q(this);
02298         if (q.getStatus())
02299           return q.getStatus();
02300       
02301         Status s = q.scan(*read_cache.oid_arr);
02302         if (s || read_cache_state_oid == coherent) return s;
02303       }
02304     else if (read_cache_state_oid == coherent)
02305       return Success;
02306 
02307     if (read_cache_state_oid == coherent)
02308       {
02309         assert(CACHE_LIST_COUNT(cache) == 0);
02310         return Success;
02311       }
02312 
02313     ValueItem *item;
02314     OidList *oid_list = read_cache.oid_arr->toList();
02315 
02316     if (cache) {
02317       ValueCache::IdMapIterator begin = cache->getIdMap().begin();
02318       ValueCache::IdMapIterator end = cache->getIdMap().end();
02319 
02320       while (begin != end) {
02321         item = (*begin).second;
02322         const Value &v = item->getValue();
02323         if (v.type == Value::tOid) {
02324           Oid item_oid = *v.oid;
02325 
02326           int s = item->getState();
02327 
02328 #ifdef NEW_GET_ELEMENTS
02329           if (s == removed) {
02330             if (item_oid.isValid())
02331               oid_list->suppressOid(item_oid);
02332           }
02333           else if (s == added) {
02334             oid_list->insertOidLast(item_oid);
02335           }
02336 #else
02337           if (s == removed && item_oid.isValid())
02338             oid_list->suppressOid(item_oid);
02339           else if (s == added) {
02340             if (!item_oid.isValid() || !oid_list->exists(item_oid))
02341               oid_list->insertOidLast(item_oid);
02342           }
02343 #endif
02344         }
02345         ++begin;
02346       }
02347     }
02348 
02349     delete read_cache.oid_arr;
02350     read_cache.oid_arr = oid_list->toArray();
02351     delete oid_list;
02352 
02353     read_cache_state_oid = coherent;
02354     return Success;
02355   }
02356 
02357   Status Collection::getElements(ObjectPtrVector &obj_vect,
02358                                  const RecMode *rcm) const
02359   {
02360     ObjectArray obj_array; // true or false;
02361     Status s = getElements(obj_array, rcm);
02362     if (s)
02363       return s;
02364     obj_array.makeObjectPtrVector(obj_vect);
02365     return Success;
02366   }
02367 
02368   Status Collection::getElements(ObjectArray &obj_array,
02369                                  const RecMode *rcm) const
02370   {
02371     if (status)
02372       return Exception::make(status);
02373 
02374 #ifdef TRY_GETELEMS_GC
02375     if (obj_array.isAutoGarbage()) {
02376       return Exception::make(IDB_ERROR,
02377                              "Collection::getElements(ObjectArray &): "
02378                              "ObjectArray argument cannot be in auto-garbaged mode");
02379     }
02380 #endif
02381 
02382     if (!isref && !coll_class->asBasicClass() &&
02383         !coll_class->asEnumClass()) {
02384       ValueArray val_arr;
02385       Status s = getElements(val_arr, False);
02386       if (s) return s;
02387       int count = val_arr.getCount();
02388       obj_array.set(0, count);
02389       for (int n = 0; n < count; n++) {
02390         if (val_arr[n].getType() == Value::tObject)
02391           obj_array.setObjectAt(n, val_arr[n].o); //obj_array[n] = val_arr[n].o;
02392         else if (val_arr[n].getType() == Value::tObjectPtr)
02393           obj_array.setObjectAt(n, val_arr[n].o_ptr->getObject());
02394         else
02395           return Exception::make(IDB_ERROR, "unexpected value type");
02396       }
02397       return Success;
02398     }
02399 
02400     Status s = const_cast<Collection *>(this)->getObjElementsRealize(rcm);
02401     if (s) return s;
02402 
02403     obj_array = *read_cache.obj_arr;
02404     return Success;
02405   }
02406 
02407   Status
02408   Collection::getObjElementsRealize(const RecMode *rcm)
02409   {
02410     if (!isref) {
02411       return Exception::make(IDB_COLLECTION_ERROR,
02412                              "cannot get object elements");
02413     }
02414 
02415     IDB_COLL_LOAD_DEFERRED();
02416 
02417     if (read_cache.obj_arr && read_cache_state_object == coherent)
02418       return Success;
02419 
02420 #ifdef TRY_GETELEMS_GC
02421     assert(!read_cache.obj_arr || read_cache.obj_arr->isAutoGarbage());
02422     assert(!read_cache.val_arr || read_cache.val_arr->isAutoObjGarbage());
02423 #endif
02424     delete read_cache.obj_arr;
02425 
02426     // 31/10/06: changed because of a memory leaks bug
02427     // but not really shure that could not have side effect
02428     //    read_cache.obj_arr = new ObjectArray();
02429 #ifdef TRY_GETELEMS_GC
02430     read_cache.obj_arr = new ObjectArray(true);
02431 #else
02432     read_cache.obj_arr = new ObjectArray();
02433 #endif
02434 
02435     if (getOidC().isValid()) {
02436       Iterator q(this);
02437       if (q.getStatus())
02438         return q.getStatus();
02439           
02440       Status s = q.scan(*read_cache.obj_arr);
02441       if (s || read_cache_state_object == coherent)
02442         return s;
02443     }
02444     else if (read_cache_state_object == coherent)
02445       return Success;
02446 
02447     if (read_cache_state_object == coherent) {
02448       assert(CACHE_LIST_COUNT(cache) == 0);
02449       return Success;
02450     }
02451 
02452     ValueItem *item;
02453 
02454     ObjectList *obj_list = read_cache.obj_arr->toList();
02455 
02456 #if 0
02457 #ifdef TRY_GETELEMS_GC
02458     // 31/10/06: see above
02459     {
02460       Object *oo;
02461       ObjectListCursor c(obj_list);
02462 
02463       while (c.getNext(oo)) {
02464         oo->incrRefCount();
02465         printf("incrRefCount #1 %p %d\n", oo, oo->getRefCount());
02466       }
02467     }
02468 #endif
02469 #endif
02470 
02471     if (cache) {
02472       ValueCache::IdMapIterator begin = cache->getIdMap().begin();
02473       ValueCache::IdMapIterator end = cache->getIdMap().end();
02474 
02475       while (begin != end) {
02476         item = (*begin).second;
02477         const Value &v = item->getValue();
02478         Object *item_o = 0;
02479         if (v.type == Value::tOid) {
02480           Oid item_oid = *v.oid;
02481           if (item_oid.isValid() && db) {
02482             Status s = db->loadObject(item_oid, item_o);
02483             if (s)
02484               return s; // what about garbage??
02485           }
02486         }
02487         else if (v.type == Value::tObject)
02488           item_o = v.o;
02489         else if (v.type == Value::tObjectPtr)
02490           item_o = v.o_ptr->getObject();
02491 
02492         if (!item_o)
02493           return Exception::make(IDB_INTERNAL_ERROR, "invalid null object "
02494                                  "found in Collection::getObjElementsRealize()");
02495 
02496         int s = item->getState();
02497 
02498 #ifdef NEW_GET_ELEMENTS
02499         if (s == removed)
02500           obj_list->suppressObject(item_o);
02501         else if (s == added) {
02502           obj_list->insertObjectLast(item_o);
02503           item_o->incrRefCount();
02504 #else
02505         if (s == removed)
02506           obj_list->suppressObject(item_o);
02507         else if (s == added) {
02508           obj_list->insertObjectLast(item_o);
02509           item_o->incrRefCount();
02510 #endif
02511         }
02512 
02513         ++begin;
02514       }
02515     }
02516 
02517 #ifdef TRY_GETELEMS_GC
02518     assert(!read_cache.obj_arr || read_cache.obj_arr->isAutoGarbage());
02519     assert(!read_cache.val_arr || read_cache.val_arr->isAutoObjGarbage());
02520 #endif
02521     delete read_cache.obj_arr;
02522 
02523     /*
02524 #ifdef TRY_GETELEMS_GC
02525     {
02526       Object *oo;
02527       ObjectListCursor c(obj_list);
02528 
02529       while (c.getNext(oo)) {
02530         printf("refCount #3 %p %d\n", oo, oo->getRefCount());
02531       }
02532     }
02533 #endif
02534     */
02535 
02536     read_cache.obj_arr = obj_list->toArray();
02537 #ifdef TRY_GETELEMS_GC
02538     read_cache.obj_arr->setAutoGarbage(true);
02539     read_cache.obj_arr->setMustRelease(false);
02540 #endif
02541 
02542     /*
02543 #ifdef TRY_GETELEMS_GC
02544     {
02545       Object *oo;
02546       ObjectListCursor c(obj_list);
02547 
02548       while (c.getNext(oo)) {
02549         printf("refCount #4 %p %d\n", oo, oo->getRefCount());
02550       }
02551     }
02552 #endif
02553     */
02554 
02555     delete obj_list;
02556 
02557     read_cache_state_object = coherent;
02558     return Success;
02559   }
02560 
02561   void
02562   Collection::emptyReadCache()
02563   {
02564     // WARNING DISCONNECTED the 20/01/00 because of a memory bug!
02565     /*
02566       if (read_cache.obj_arr)
02567       read_cache.obj_arr->garbage();
02568     */
02569 
02570     // 31/10/06: the previous disconnection leads to a memory leaks (sometimes)
02571     // so...
02572 
02573 #ifdef TRY_GETELEMS_GC
02574     assert(!read_cache.obj_arr || read_cache.obj_arr->isAutoGarbage());
02575     assert(!read_cache.val_arr || read_cache.val_arr->isAutoObjGarbage());
02576 #endif
02577     delete read_cache.obj_arr;
02578 
02579     delete read_cache.oid_arr;
02580     delete read_cache.val_arr;
02581     read_cache.obj_arr = 0;
02582     read_cache.oid_arr = 0;
02583     read_cache.val_arr = 0;
02584     unvalidReadCache();
02585   }
02586 
02587 #define CONVERT(VALUE_ARRAY, TYPE, OFF) \
02588 do { \
02589   for (int i = (OFF); i < (VALUE_ARRAY)->value_cnt; i += (OFF)+1) \
02590     { \
02591       Value v = (VALUE_ARRAY)->values[i]; \
02592       TYPE k; \
02593       memcpy(&k, v.data, sizeof(TYPE)); \
02594       (VALUE_ARRAY)->values[i].set(k); \
02595     } \
02596 } while(0)
02597 
02598   static int
02599   value_index_cmp (const void *x1, const void *x2)
02600   {
02601     Value *v1 = (Value *)x1;
02602     Value *v2 = (Value *)x2;
02603     return v1->i - v2->i;
02604   }
02605 
02606   static void
02607   sortValues(ValueArray &value_array)
02608   {
02609     qsort(value_array.getValues(), value_array.getCount()/2, 2*sizeof(Value),
02610           value_index_cmp);
02611   }
02612 
02613   Status
02614   Collection::getElements(ValueArray &value_array, Bool index) const
02615   {
02616     if (status)
02617       return Exception::make(status);
02618 
02619 #ifdef TRY_GETELEMS_GC
02620     if (value_array.isAutoObjGarbage()) {
02621       return Exception::make(IDB_ERROR,
02622                              "Collection::getElements(ValueArray &): "
02623                              "ValueArray argument cannot be in auto-object-garbaged mode");
02624     }
02625 #endif
02626 
02627     Status s =  const_cast<Collection *>(this)->getValElementsRealize(index);
02628     if (s) return s;
02629 
02630     value_array = *read_cache.val_arr;
02631     return Success;
02632   }
02633 
02634   Status
02635   Collection::getValElementsRealize(Bool index)
02636   {
02637     IDB_COLL_LOAD_DEFERRED();
02638 
02639     if (read_cache.val_arr &&
02640         read_cache_state_value == coherent &&
02641         read_cache_state_index == index)
02642       return Success;
02643  
02644     delete read_cache.val_arr;
02645 #ifdef TRY_GETELEMS_GC
02646     read_cache.val_arr = new ValueArray(true);
02647 #else
02648     read_cache.val_arr = new ValueArray();
02649 #endif
02650 
02651     if (getOidC().isValid()) {
02652       Iterator q(this, index);
02653       if (q.getStatus())
02654         return q.getStatus();
02655       
02656       Status s = q.scan(*read_cache.val_arr);
02657       
02658       if (s) return s;
02659     }
02660 
02661     if (read_cache_state_value == coherent &&
02662         read_cache_state_index == index) {
02663       assert(CACHE_LIST_COUNT(cache) == 0);
02664       /*
02665       int idx = (index ? 1 : 0);
02666       for (int i = idx; i < read_cache.val_arr->value_cnt; i += idx+1)
02667         if (read_cache.val_arr->values[i].type == Value::tObject)
02668           read_cache.val_arr->values[i].o->incrRefCount();
02669       */
02670       return Success;
02671     }
02672 
02673     if (read_cache_state_value != coherent ||
02674         read_cache_state_index != index) {
02675       ValueItem *item;
02676       ValueList *value_list = read_cache.val_arr->toList();
02677       
02678       // IMPORTANT NOTICE 15/08/06
02679       // Two bugs
02680       // - does not work when index is true
02681       // - the test 'if (!value_list->exists(item_value)' is not correct
02682       //   in case of the collection contains duplicate elements (not sets,
02683       //   but bags and arrays).
02684       //   The exists method should deal with pointers and not values.
02685       //   The problem is the same for getOidElements and getObjElements
02686       //   Question : why do we need value_list in case of cache is not
02687       //   coherent ?
02688       // patchs for these bugs : #define NEW_GET_ELEMENTS
02689 
02690       if (cache) {
02691         ValueCache::IdMapIterator begin = cache->getIdMap().begin();
02692         ValueCache::IdMapIterator end = cache->getIdMap().end();
02693 
02694 #ifdef NEW_GET_ELEMENTS
02695         while (begin != end) {
02696           item = (*begin).second;
02697           const Value &item_value = item->getValue();
02698           
02699           int s = item->getState();
02700           if (s == removed) {
02701             /*
02702             if (index)
02703               value_list->suppressValue(Value((int)(*begin).first));
02704             value_list->suppressValue(item_value);
02705             */
02706             if (index)
02707               value_list->suppressPairValues(Value((int)(*begin).first),
02708                                              item_value);
02709             else
02710               value_list->suppressValue(item_value);
02711           }
02712           else if (s == added) {
02713             if (item_value.type == Value::tObject)
02714               item_value.o->incrRefCount();
02715             if (index)
02716               value_list->insertValueLast(Value((int)(*begin).first));
02717             value_list->insertValueLast(item_value);
02718           }
02719 #else
02720         while (begin != end) {
02721           item = (*begin).second;
02722           const Value &item_value = item->getValue();
02723           
02724           int s = item->getState();
02725           if (s == removed)
02726             value_list->suppressValue(item_value);
02727           else if (s == added) {
02728             if (!value_list->exists(item_value)) {
02729               if (item_value.type == Value::tObject)
02730                 item_value.o->incrRefCount();
02731               value_list->insertValueLast(item_value);
02732             }
02733           }
02734 #endif
02735           ++begin;
02736         }
02737       }
02738       
02739       delete read_cache.val_arr;
02740       read_cache.val_arr = value_list->toArray();
02741 #ifdef TRY_GETELEMS_GC
02742       read_cache.val_arr->setAutoObjGarbage(true);
02743       read_cache.val_arr->setMustRelease(false);
02744 #endif
02745       delete value_list;
02746       
02747       read_cache_state_value = coherent;
02748       read_cache_state_index = index;
02749     }
02750     
02751     if (index && (asCollArray() || asCollList()))
02752       sortValues(*read_cache.val_arr);
02753 
02754     int idx = (index ? 1 : 0);
02755 
02756     if (isref) {
02757       /*
02758       for (int i = idx; i < read_cache.val_arr->value_cnt; i += idx+1)
02759         if (read_cache.val_arr->values[i].type == Value::tObject)
02760           read_cache.val_arr->values[i].o->incrRefCount();
02761       */
02762       return Success;
02763     }
02764 
02765     // 9/9/05: must take dim into account !!!
02766     // Value is of type DATA and is not decoded (XDR) :
02767     // - must decode here
02768     // - before, in IteratorAtom::decode ??
02769 
02770     unsigned int value_cnt = read_cache.val_arr->getCount();
02771     for (int i = idx; i < value_cnt; i += idx+1) {
02772       makeValue(const_cast<Value&>((*read_cache.val_arr)[i])); // makeValue(read_cache.val_arr->values[i]);
02773       /*
02774       if (read_cache.val_arr->values[i].type == Value::tObject)
02775         read_cache.val_arr->values[i].o->incrRefCount();
02776       */
02777     }
02778 
02779     
02780     return Success;
02781   }
02782 
02783   void Collection::makeValue(Value &v) {
02784     if (v.type == Value::tData &&
02785         !isref && !coll_class->asBasicClass() && !coll_class->asEnumClass()) {
02786       Database::consapp_t consapp = getDatabase()->getConsApp(coll_class);
02787       Object *o;
02788       if (consapp) {
02789         o = consapp(coll_class, 0);
02790         memcpy(o->getIDR() + IDB_OBJ_HEAD_SIZE, v.data.data, item_size);
02791       }
02792       else
02793         o = coll_class->newObj(v.data.data, True);
02794       
02795       o->setDatabase(getDatabase());
02796       v.set(o);
02797     }
02798   }
02799 
02800   Status Collection::failedCardinality() const
02801   {
02802     return Exception::make(IDB_CARDINALITY_CONSTRAINT_ERROR,
02803                            "items count %d does not respect constraint '%s'",
02804                            v_items_cnt, card->getString());
02805   }
02806 
02807   Status Collection::checkCardinality() const
02808   {
02809 #ifdef CARD_TRACE
02810     printf("Collection::checkCardinality()\n");
02811 #endif
02812     if (status != Success)
02813       return Exception::make(IDB_COLLECTION_ERROR,
02814                              "invalid collection status: \"%s\"",
02815                              status->getDesc());
02816 
02817     if (!card)
02818       return Success;
02819 
02820     if (card_bottom_excl && (v_items_cnt <= card_bottom))
02821       return failedCardinality();
02822 
02823     if (!card_bottom_excl && (v_items_cnt < card_bottom))
02824       return failedCardinality();
02825 
02826     if (card_top == CardinalityConstraint::maxint)
02827       return Success;
02828 
02829     if (card_top_excl && (v_items_cnt >= card_top))
02830       return failedCardinality();
02831 
02832     if (!card_top_excl && (v_items_cnt > card_top))
02833       return failedCardinality();
02834 
02835     return Success;
02836   }
02837 
02838   Status Collection::realizeCardinality()
02839   {
02840     printf("Collection::realizeCardinality(%p)\n", card);
02841     if (!card)
02842       return Success;
02843 
02844     if (status != Success)
02845       return Exception::make(IDB_COLLECTION_ERROR,
02846                              "invalid collection status: \"%s\"",
02847                              status->getDesc());
02848 
02849     if (!getOidC().isValid())
02850       return Exception::make(IDB_COLLECTION_ERROR, "collection oid '%s' is not valid", name);
02851 
02852     IDB_CHECK_WRITE(db);
02853 
02854     Data temp = 0;
02855     Offset offset = IDB_OBJ_HEAD_SIZE;
02856     Size alloc_size = 0;
02857 
02858     cardCode(temp, offset, alloc_size);
02859 
02860     ObjectHeader hdr;
02861     memset(&hdr, 0, sizeof(hdr));
02862 
02863     hdr.type = type;
02864     hdr.size = alloc_size;
02865     hdr.xinfo = IDB_XINFO_CARD;
02866 
02867     offset = 0;
02868 
02869     object_header_code(&temp, &offset, &alloc_size, &hdr);
02870 
02871     RPCStatus rpc_status;
02872 
02873     rpc_status = objectWrite(db->getDbHandle(), temp, getOidC().getOid());
02874 
02875     free(temp);
02876 
02877     return StatusMake(IDB_COLLECTION_ERROR, rpc_status);
02878   }
02879 
02880   Status
02881   Collection::cache_compile(Offset &offset,
02882                             Size &alloc_size,
02883                             unsigned char **ptemp,
02884                             const RecMode *rcm)
02885   {
02886     Status _status;
02887 
02888     if (_status = checkCardinality())
02889       return _status;
02890 
02891     unsigned int count = CACHE_LIST_COUNT(cache);
02892 
02893     alloc_size = IDB_OBJ_HEAD_SIZE + 2 * sizeof(eyedblib::int32) +
02894       (count * (item_size + sizeof(eyedblib::int32) + sizeof(char)));
02895 
02896     // idx_data_size + idx_data
02897     //  alloc_size += sizeof(eyedblib::int16) + idx_data_size;
02898 
02899     offset = IDB_OBJ_HEAD_SIZE;
02900 
02901     unsigned char *temp = (unsigned char *)malloc(alloc_size);
02902     //unsigned char *temp = 0;
02903 
02904     int32_code (&temp, &offset, &alloc_size, &v_items_cnt);
02905 
02906     int skip_cnt = 0;
02907     Offset list_cnt_offset = offset;
02908     eyedblib::int32 kh = count;
02909     int32_code (&temp, &offset, &alloc_size, &kh);
02910 
02911     ValueItem *item;
02912 
02913     if (cache) {
02914       ValueCache::IdMapIterator begin = cache->getIdMap().begin();
02915       ValueCache::IdMapIterator end = cache->getIdMap().end();
02916 
02917       begin = cache->getIdMap().begin();
02918       end = cache->getIdMap().end();
02919 
02920       while (begin != end) {
02921         item = (*begin).second;
02922         const Value &v = item->getValue();
02923 
02924         if (isref)  {
02925           Oid _oid;
02926           Object *_o = 0;
02927 
02928           if (v.type == Value::tObject)
02929             _o = v.o;
02930           else if (v.type == Value::tObjectPtr)
02931             _o = v.o_ptr->getObject();
02932 
02933           if (_o) {
02934             if (item->getState() == added &&
02935                 rcm->getType() == RecMode_FullRecurs)  {
02936               Status _status = _o->realize(rcm);
02937               if (_status) {
02938                 free(temp);
02939                 return _status;
02940               }
02941             }
02942             _oid = _o->getOid();
02943           }
02944           else
02945             _oid = *v.oid;
02946 
02947           if (!_oid.isValid() && item->getState() == removed) {
02948             skip_cnt++;
02949             ++begin;
02950             continue;
02951           }
02952 
02953           if (!_oid.isValid() && item->getState() == added)
02954             return Exception::make(IDB_COLLECTION_ERROR,
02955                                    "cannot insert a null oid into "
02956                                    "a collection: must store first "
02957                                    "collection elements");
02958           
02959           oid_code(&temp, &offset, &alloc_size, _oid.getOid());
02960         }
02961         else {
02962           buffer_code   (&temp, &offset, &alloc_size, v.getData(),
02963                          item_size);
02964 
02965         }
02966 
02967 
02968         Collection::ItemId id = item->getId();
02969         int32_code (&temp, &offset, &alloc_size, (int*)&id);
02970         char kc = (char)item->getState();
02971         char_code (&temp, &offset, &alloc_size, &kc);
02972         ++begin;
02973       }
02974     }
02975     
02976     if (skip_cnt) {
02977       kh -= skip_cnt;
02978       int32_code (&temp, &list_cnt_offset, &alloc_size, &kh);
02979     }
02980 
02981     *ptemp = temp;
02982 
02983     return Success;
02984   }
02985 
02986   Status
02987   collectionMake(Database *db, const Oid *oid, Object **o,
02988                      const RecMode *rcm, const ObjectHeader *hdr,
02989                      Data idr, LockMode lockmode, const Class *_class)
02990   {
02991     RPCStatus rpc_status;
02992     Data temp;
02993     Oid _oid(hdr->oid_cl);
02994 
02995     if (_oid.isValid())
02996       {
02997         Oid xoid(hdr->oid_cl);
02998         if (!_class)
02999           _class = db->getSchema()->getClass(hdr->oid_cl, True);
03000         if (!_class)
03001           return Exception::make(IDB_CLASS_NOT_FOUND, "collection class '%s'",
03002                                  OidGetString(&hdr->oid_cl));
03003       }
03004     else
03005       _class = 0;
03006 
03007     if (!idr)
03008       {
03009         temp = (unsigned char *)malloc(hdr->size);
03010         object_header_code_head(temp, hdr);
03011       
03012         rpc_status = objectRead(db->getDbHandle(), temp, 0, 0, oid->getOid(),
03013                                     0, lockmode, 0);
03014       }
03015     else
03016       {
03017         temp = idr;
03018         rpc_status = RPCSuccess;
03019       }
03020 
03021     if (rpc_status != RPCSuccess)
03022       return StatusMake(rpc_status);
03023 
03024     char locked;
03025     Object *card;
03026     int items_cnt, bottom, top;
03027     char *name;
03028     Oid idx1_oid, idx2_oid;
03029     Oid inv_oid;
03030     eyedblib::int16 inv_item = 0;
03031     Bool is_literal = False;
03032     Bool is_pure_literal = False;
03033     Data idx_data = 0;
03034     Size idx_data_size = 0;
03035     IndexImpl *idximpl = 0;
03036 
03037     if (ObjectPeer::isRemoved(*hdr)) {
03038       locked = 0;
03039       card = NULL;
03040       idximpl = 0;
03041       items_cnt = bottom = top = 0;
03042       name = "";
03043     }
03044     else {
03045       Offset offset = IDB_OBJ_HEAD_SIZE;
03046     
03047       char_decode (temp, &offset, &locked);
03048     
03049       /* item_size */
03050       eyedblib::int16 kk;
03051       int16_decode (temp, &offset, &kk);
03052 
03053       Status s = IndexImpl::decode(db, temp, offset, idximpl);
03054       if (s) return s;
03055 
03056       oid_decode (temp, &offset, idx1_oid.getOid());
03057       oid_decode (temp, &offset, idx2_oid.getOid());
03058       int32_decode (temp, &offset, &items_cnt);
03059       int32_decode (temp, &offset, &bottom);
03060       int32_decode (temp, &offset, &top);
03061 
03062       card = Collection::cardDecode(db, temp, offset);
03063 
03064       eyedbsm::Oid se_inv_oid;
03065       oid_decode(temp, &offset, &se_inv_oid); 
03066       inv_oid.setOid(se_inv_oid);
03067       int16_decode(temp, &offset, &inv_item);
03068 
03069       char c;
03070       /* is_literal */
03071       LITERAL_OFFSET = offset;
03072       char_decode (temp, &offset, &c);
03073       Collection::decodeLiteral(c, is_literal, is_pure_literal);
03074 
03075       //is_literal = IDBBOOL(c);
03076       /* idx_data */
03077       eyedblib::int16 sz;
03078       int16_decode (temp, &offset, &sz);
03079       idx_data_size = sz;
03080       idx_data = temp+offset;
03081       offset += idx_data_size;
03082 
03083       string_decode(temp, &offset, &name);
03084     }
03085   
03086 #ifdef COLLTRACE
03087     printf("collection make idx_data_size=%d\n", idx_data_size);
03088 #endif
03089     if (eyedb_is_type(*hdr, _CollSet_Type))
03090       *o = (Object *)CollectionPeer::collSet
03091         (name, (Class *)_class, idx1_oid, idx2_oid, items_cnt,
03092          bottom, top, idximpl, card, is_literal, is_pure_literal, idx_data, idx_data_size);
03093 
03094     else if (eyedb_is_type(*hdr, _CollBag_Type))
03095       *o = (Object *)CollectionPeer::collBag
03096         (name, (Class *)_class, idx1_oid, idx2_oid, items_cnt,
03097          bottom, top, idximpl, card, is_literal, is_pure_literal, idx_data, idx_data_size);
03098 
03099     else if (eyedb_is_type(*hdr, _CollList_Type))
03100       *o = (Object *)CollectionPeer::collList
03101         (name, (Class *)_class, idx1_oid, idx2_oid, items_cnt,
03102          bottom, top, idximpl, card, is_literal, is_pure_literal, idx_data, idx_data_size);
03103 
03104     else if (eyedb_is_type(*hdr, _CollArray_Type))
03105       *o = (Object *)CollectionPeer::collArray
03106         (name, (Class *)_class, idx1_oid, idx2_oid, items_cnt,
03107          bottom, top, idximpl, card, is_literal, is_pure_literal, idx_data, idx_data_size);
03108 
03109     else {
03110       if (idximpl)
03111         idximpl->release();
03112       return Exception::make(IDB_INTERNAL_ERROR, "invalid collection type: "
03113                              "%p", hdr->type);
03114     }
03115 
03116 
03117     if (idximpl)
03118       idximpl->release();
03119     CollectionPeer::setLock((Collection *)*o, (Bool)locked);
03120 
03121     if (is_literal)
03122       (*o)->asCollection()->setLiteralOid(*oid);
03123 
03124     if (inv_oid.isValid())
03125       CollectionPeer::setInvOid((Collection *)*o, inv_oid, inv_item);
03126 
03127     if (!idr)
03128       free(temp);
03129 
03130     return Success;
03131   }
03132 
03133   Status
03134   Collection::getImplementation(IndexImpl *&_idximpl, Bool remote) const
03135   {
03136     if (!remote) {
03137       if (is_literal) {
03138         Status s = const_cast<Collection *>(this)->loadDeferred();
03139         if (s) return s;
03140       }
03141       _idximpl = idximpl->clone();
03142       return Success;
03143     }
03144 
03145     _idximpl = 0;
03146 
03147     Oid idx1oid, idx2oid;
03148     Status s = getIdxOid(idx1oid, idx2oid);
03149     if (s) return s;
03150 
03151     if (idx1oid.isValid()) {
03152       RPCStatus rpc_status =
03153         collectionGetImplementation(db->getDbHandle(),
03154                                         idximpl->getType(),
03155                                         idx1oid.getOid(), (Data *)&_idximpl);
03156       if (rpc_status)
03157         return StatusMake(rpc_status);
03158     
03159       _idximpl->setHashMethod(idximpl->getHashMethod());
03160     }
03161 
03162     return Success;
03163   }
03164 
03165   Status
03166   Collection::literalMake(Collection *o)
03167   {
03168 #if 1
03169     is_literal = o->isLiteral();
03170     is_pure_literal = o->isPureLiteral();
03171 #endif
03172 
03173     assert(literal_oid == o->getOid());
03174     oid.invalidate();
03175     literal_oid = o->getOid();
03176 
03177 #if 0
03178     //printf("o->isLiteral %d %d\n", o->isLiteral(), o->isPureLiteral());
03179     Status s = loadLiteral();
03180     if (s)
03181       return s;
03182     //printf("isLiteral %d %d\n", isLiteral(), isPureLiteral());
03183 
03184     if (o->isLiteral() != isLiteral() || o->isPureLiteral() != isPureLiteral())
03185       printf("---------------------------- ARGH -----------------------\n");
03186 #endif
03187 
03188 #ifdef COLLTRACE
03189     printf("literalMake:: literal oid is %s\n", literal_oid.toString());
03190 #endif
03191     /*
03192       printf("type %d %d name '%s' '%s' ordered %d %d allow_dup %d %d "
03193       "string_coll %d %d",
03194       type, o->type, name, o->name, ordered, o->ordered,
03195       allow_dup, o->allow_dup, string_coll, o->string_coll);
03196       printf("isref %d %d\n", isref, o->isref);
03197       printf("coll_class %p %p\n", coll_class, o->coll_class);
03198       printf("cache before %p %d %d %d\n",
03199       cache, read_cache.obj_arr, read_cache.oid_arr, read_cache.val_arr);
03200 
03201       printf("cl_oid %s %s\n", cl_oid.toString(), o->cl_oid.toString());
03202     */
03203 
03204     bottom = o->bottom;
03205     top = o->top;
03206     locked = o->locked;
03207     inv_oid = o->inv_oid;
03208     inv_item = o->inv_item;
03209   
03210     card = (CardinalityDescription *)CLONE(o->card);
03211     card_bottom = o->card_bottom;
03212     card_bottom_excl = o->card_bottom_excl;
03213     card_top = o->card_top;
03214     card_top_excl = o->card_top_excl;
03215     card_oid = o->card_oid;
03216 
03217     if (db && db->isBackEnd())
03218       {
03219         idx1_oid = o->idx1_oid;
03220         idx2_oid = o->idx2_oid;
03221         idx1 = o->idx1;
03222         idx2 = o->idx2;
03223       }
03224 
03225     // added the 25/11/99
03226     delete cache;
03227     // ...
03228     cache = o->cache;
03229     if (cache)
03230       cache->setObject(this);
03231 
03232     o->cache = 0;
03233     p_items_cnt = o->p_items_cnt;
03234     v_items_cnt = o->v_items_cnt;
03235     inverse_valid = o->inverse_valid;
03236     if (!implModified) {
03237       if (idximpl)
03238         idximpl->release();
03239       idximpl = o->idximpl->clone();
03240     }
03241     /*
03242       printf("literalMake idr=%p o_idr=%p refcnt=%d o_refcnt=%d\n",
03243       data, o->idr->idr, idr->refcnt, o->idr->refcnt);
03244     */
03245     return Success;
03246   }
03247 
03248   //
03249   // WARNING: the literal_oid MUST BE the first field of the idr for
03250   // literal collections because of inverse implementation.
03251   //
03252 
03253   Status
03254   Collection::realizePerform(const Oid& cloid,
03255                              const Oid& objoid,
03256                              AttrIdxContext &idx_ctx,
03257                              const RecMode *rcm)
03258   {
03259     assert(is_literal);
03260 
03261     CHK_OBJ(this);
03262 
03263 #ifdef COLLTRACE
03264     printf("Collection::realizePerform(%p)\n", this);
03265 
03266     Object *master_obj = getMasterObject(true);
03267     printf("master_object %p\n", master_obj);
03268     if (master_obj)
03269       printf("MASTER_OBJECT %s %s [%s]\n",
03270              master_obj->getOid().toString(),
03271              master_obj->getClass()->getName(), idx_ctx.getString().c_str());
03272 #endif
03273     if (!idx_data)
03274       idx_data = idx_ctx.code(idx_data_size);
03275 
03276     void *ud = setUserData(IDB_MAGIC_COLL);
03277     Status s = realize(rcm);
03278     (void)setUserData(ud);
03279     if (s)
03280       return s;
03281 
03282 #ifdef COLLTRACE
03283     printf("Collection::realizePerform(-> %s, %p)\n", literal_oid.toString(),
03284            idx_data);
03285 #endif
03286 
03287     Offset offset = IDB_OBJ_HEAD_SIZE;
03288     Size alloc_size = idr->getSize();
03289     Data data = idr->getIDR();
03290 
03291 #if 0
03292     eyedbsm::Oid hoid;
03293     oid_decode(data, &offset, &hoid);
03294     printf("before coding %s on %p\n", Oid(hoid).toString(), data);
03295     offset = IDB_OBJ_HEAD_SIZE;
03296     printf("coding %s on %p\n", literal_oid.toString(), data);
03297 #endif
03298 
03299     oid_code(&data, &offset, &alloc_size, literal_oid.getOid());
03300 
03301     return Success;
03302   }
03303 
03304   Status
03305   Collection::loadPerform(const Oid&, LockMode lockmode,
03306                           AttrIdxContext &idx_ctx,
03307                           const RecMode *rcm)
03308   {
03309     Offset offset = IDB_OBJ_HEAD_SIZE;
03310     oid_decode(idr->getIDR(), &offset, literal_oid.getOid());
03311 
03312 #ifdef COLLTRACE
03313     Object *master_obj = getMasterObject(true);
03314     printf("master_object %p %s %s [%s]\n",
03315            master_obj, master_object->getOid().toString(),
03316            master_obj->getClass()->getName(),
03317            (const char *)idx_ctx.getString());
03318 
03319     printf("Collection::loadPerform(%p, %s)\n", this, literal_oid.toString());
03320 #endif
03321 
03322     if (!idx_data)
03323       idx_data = idx_ctx.code(idx_data_size);
03324 
03325     // 17/09/01: moved from bottom
03326     if (literal_oid.isValid())
03327       is_complete = False;
03328 
03329     if (rcm == RecMode::NoRecurs)
03330       {
03331         // 17/09/01: moved this code above ^
03332         /*
03333           if (literal_oid.isValid())
03334           is_complete = False;
03335         */
03336         return Success;
03337       }
03338 
03339     return Collection::loadDeferred(lockmode, rcm);
03340   }
03341 
03342   Status
03343   Collection::loadDeferred(LockMode lockmode, const RecMode *rcm)
03344   {
03345     if (is_complete) // added the 10/11/99
03346       return Success;
03347 
03348     Collection *o;
03349 #ifdef COLLTRACE
03350     printf("loading deferred %p %s\n", this, literal_oid.toString());
03351 #endif
03352 
03353 #ifdef COLL_OPTIM_LOAD
03354     if (!literal_oid.isValid())
03355       return Success;
03356 #endif
03357     // changed the 29/05/02
03358 #if 1
03359     Status s = db->loadObject_realize(&literal_oid, (Object **)&o,
03360                                       lockmode, rcm);
03361     if (s)
03362       return s;
03363 #else
03364     Status s = db->loadObject(literal_oid, (Object *&)o, rcm);
03365     if (s)
03366       return s;
03367 #endif
03368 
03369     s = literalMake(o);
03370     if (s)
03371       return s;
03372     /*
03373       printf("releasing initial collection object o=%p refcnt=%d "
03374       "this=%p refcnt=%d\n",
03375       o, o->getRefCount(), this, getRefCount());
03376     */
03377     o->release();
03378     is_complete = True;
03379     return Success;
03380   }
03381 
03382   Status
03383   Collection::removePerform(const Oid& cloid, 
03384                             const Oid& objoid,
03385                             AttrIdxContext &idx_ctx,
03386                             const RecMode *rcm)
03387   {
03388 #ifdef COLLTRACE
03389     printf("Collection::removePerform(%p, %s) should remove only if pure_literal %d %d\n", this,
03390            literal_oid.toString(), is_literal, is_pure_literal);
03391 #endif
03392 
03393 #ifdef COLLTRACE
03394     printf("trying to remove literal collection %s [%s]\n",
03395            literal_oid.toString(),
03396            getMasterObject(true) ? getMasterObject(true)->getOid().toString() : "<no master>");
03397 #endif
03398 
03399     Status s = loadLiteral();
03400     if (s)
03401       return s;
03402     assert(is_literal);
03403 
03404 #ifdef COLL_OPTIM_CREATE
03405     if (!literal_oid.isValid())
03406       return Success;
03407 #endif
03408     Bool was_pure_literal = is_pure_literal;
03409 
03410     is_literal = False;
03411     is_pure_literal = False;
03412 
03413     s = updateLiteral();
03414     if (s)
03415       return s;
03416 
03417     if (was_pure_literal) {
03418       s = db->removeObject(literal_oid, rcm);
03419       if (s)
03420         return s;
03421     }
03422 
03423     literal_oid.invalidate();
03424     return Success;
03425   }
03426 
03427   Status
03428   Collection::postRealizePerform(const Oid& cloid,
03429                                  const Oid& objoid,
03430                                  AttrIdxContext &idx_ctx,
03431                                  Bool &mustTouch,
03432                                  const RecMode *rcm)
03433   {
03434     mustTouch = False;
03435     if (!getOidC().isValid())
03436       return Success;
03437 
03438     //printf("postRealizePerform(%p)\n", this);
03439 
03440     // 27/06/05: disconnected
03441 #if 0
03442 #ifdef E_XDR
03443     eyedbsm::Oid xoid;
03444     eyedbsm::h2x_oid(&xoid, getOidC().getOid());
03445 #else
03446     memcpy(&xoid, getOidC().getOid());
03447 #endif
03448 
03449     // 22/05/06 : disconnected because I do not know what is it for : inverse ?
03450     // when disconnecting nothing happens
03451     Oid dataoid = idx_ctx.getDataOid();
03452     if (!dataoid.isValid()) {
03453       dataoid = objoid;
03454     }
03455 
03456 #if 1
03457     if (getenv("EYEDB_XX"))
03458       printf("not writing %s in %s [%s] at %d\n",
03459              getOidC().toString(),
03460              dataoid.toString(),
03461              objoid.toString(),
03462              idx_ctx.getOff());
03463     else if (getenv("EYEDB_ZZ"))
03464       printf("setting to NULL in %s [%s] at %d\n",
03465              dataoid.toString(),
03466              objoid.toString(),
03467              idx_ctx.getOff());
03468     else
03469       printf("writing %s in %s [%s] at %d\n",
03470              getOidC().toString(),
03471              dataoid.toString(),
03472              objoid.toString(),
03473              idx_ctx.getOff());
03474 #endif
03475     
03476     if (getenv("EYEDB_YY")) {
03477       RPCStatus rpc_status =
03478         dataWrite(db->getDbHandle(), idx_ctx.getOff() /*idr_poff*/,
03479                   sizeof(eyedbsm::Oid),
03480                   (Data)Oid::nullOid.getOid(),
03481                   dataoid.getOid());
03482 
03483       if (rpc_status)
03484         return StatusMake(IDB_COLLECTION_ERROR, rpc_status);
03485     }
03486   
03487     else if (!getenv("EYEDB_XX")) {
03488       RPCStatus rpc_status =
03489         dataWrite(db->getDbHandle(), idx_ctx.getOff() /*idr_poff*/,
03490                   sizeof(eyedbsm::Oid),
03491                   (Data)&xoid,
03492                   dataoid.getOid());
03493 
03494       if (rpc_status)
03495         return StatusMake(IDB_COLLECTION_ERROR, rpc_status);
03496     }
03497 #endif
03498   
03499     Status s;
03500 #ifdef COLLTRACE
03501     printf("postRealizePerform(%p, idx_data = %p)\n", getUserData(), idx_data);
03502 #endif
03503 
03504     if (getUserData() != IDB_MAGIC_COLL2) {
03505       // WARNING: disconnected (in)validateInverse() the 5/02/01!!!!!
03506       // the problem is that I don't know why the (in)validateInverse()
03507       // were for!
03508 
03509       //invalidateInverse(); 
03510       s = realizePerform(cloid, objoid, idx_ctx, rcm);
03511       //validateInverse();
03512     }
03513     else {
03514 #ifdef COLLTRACE
03515       printf("warning magic coll for collection %p\n", this);
03516 #endif
03517       s = realizePerform(cloid, objoid, idx_ctx, rcm);
03518     }
03519 
03520     return s;
03521   }
03522 
03523   Status
03524   Collection::moveElements(const Dataspace *dataspace)
03525   {
03526     OidArray oid_arr;
03527     Status s = getElements(oid_arr);
03528     if (s)
03529       return s;
03530 
03531     return db->moveObjects(oid_arr, dataspace);
03532   }
03533 
03534   Status
03535   Collection::getDefaultDataspace(const Dataspace *&dataspace) const
03536   {
03537     RPCStatus rpc_status;
03538     if (idx1_oid.isValid()) {
03539       int dspid;
03540       rpc_status = getDefaultIndexDataspace(db->getDbHandle(),
03541                                                 idx1_oid.getOid(),
03542                                                 1, &dspid);
03543 
03544       if (rpc_status) return StatusMake(rpc_status);
03545       return db->getDataspace(dspid, dataspace);
03546     }
03547 
03548     dataspace = 0;
03549     return Success;
03550   }
03551 
03552   Status
03553   Collection::setDefaultDataspace(const Dataspace *dataspace)
03554   {
03555     RPCStatus rpc_status;
03556     if (idx1_oid.isValid()) {
03557       rpc_status = setDefaultIndexDataspace(db->getDbHandle(),
03558                                                 idx1_oid.getOid(),
03559                                                 1, dataspace->getId());
03560 
03561       if (rpc_status) return StatusMake(rpc_status);
03562     }
03563 
03564     if (idx2_oid.isValid()) {
03565       rpc_status = setDefaultIndexDataspace(db->getDbHandle(),
03566                                                 idx2_oid.getOid(),
03567                                                 1, dataspace->getId());
03568 
03569       if (rpc_status) return StatusMake(rpc_status);
03570     }
03571 
03572     return Success;
03573   }
03574 
03575   Bool Collection::isPartiallyStored() const
03576   {
03577     return (cache != 0 && cache->size() > 0) ? True : False;
03578   }
03579 }

Generated on Mon Dec 22 18:15:52 2008 for eyedb by  doxygen 1.5.3