00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "eyedb_p.h"
00038 #include "Attribute_p.h"
00039 #include "CollectionBE.h"
00040 #include <eyedbsm/eyedbsm.h>
00041 #include "InvOidContext.h"
00042
00043 #include <assert.h>
00044
00045 #include "misc.h"
00046
00047 #define CK(X) do { \
00048 Status __s__ = (X); \
00049 if (__s__) return __s__; \
00050 } while(0)
00051
00052
00053
00054 namespace eyedb {
00055
00056 #ifdef INVDBG
00057 static void
00058 get_object_class(Database *db, const Oid &oid)
00059 {
00060 if (!oid.isValid())
00061 return;
00062
00063 Class *objcls = NULL;
00064 Status status = db->getObjectClass(oid, objcls);
00065
00066 if (status)
00067 status->print();
00068
00069 if (objcls)
00070 IDB_LOG(IDB_LOG_RELSHIP_DETAILS, ("OID %s -> %s\n", oid.toString(), objcls->getName()));
00071 }
00072 #else
00073 #define get_object_class(x, y)
00074 #endif
00075
00076 static Status
00077 inverse_coll_realize(Collection *&coll)
00078 {
00079 coll->invalidateInverse();
00080 Status s = coll->realize();
00081 coll->validateInverse();
00082 coll->release(); coll = 0;
00083 return s;
00084 }
00085
00086 static Status
00087 requalify(Database *db, const Oid &obj_oid,
00088 const Attribute *&inv_item)
00089 {
00090 if (!obj_oid.isValid())
00091 return Success;
00092
00093 Class *objcls = 0;
00094 Status status = db->getObjectClass(obj_oid, objcls);
00095 if (status) return status;
00096
00097 if (objcls->getOid() == inv_item->getClassOwner()->getOid())
00098 return Success;
00099
00100 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00101 ("Attribute::inverse_realize(requalifying inverse item "
00102 "%s::%s for %s\n",
00103 inv_item->getClassOwner()->getName(),
00104 inv_item->getName(), obj_oid.toString()));
00105
00106
00107
00108
00109
00110
00111
00112 inv_item = objcls->getAttribute(inv_item->getName());
00113
00114 assert(inv_item);
00115 return Success;
00116 }
00117
00118 Status
00119 Attribute::checkInverse(const Attribute *item) const
00120 {
00121 if (!item)
00122 item = this;
00123
00124 if (item->isVarDim())
00125 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00126 "'%s' cannot make inverse on variable "
00127 "dimension attribute", item->name);
00128
00129 if (!item->cls->asCollectionClass() && !item->cls->asAgregatClass())
00130 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00131 "'%s' cannot make inverse on mateagregat "
00132 "or collection_class attribute", item->name);
00133
00134 if (item->typmod.pdims > 1)
00135 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00136 "'%s' cannot make inverse on non "
00137 "single dimension attribute", item->name);
00138
00139 return Success;
00140 }
00141
00142 void
00143 Attribute::getInverse(const char **cname, const char **fname,
00144 const Attribute **item) const
00145 {
00146 if (cname)
00147 *cname = inv_spec.clsname;
00148 if (fname)
00149 *fname = inv_spec.fname;
00150 if (item)
00151 *item = inv_spec.item;
00152 }
00153
00154 Bool Attribute::hasInverse() const
00155 {
00156 return inv_spec.item ? True : False;
00157 }
00158
00159 Status Attribute::setInverse(const Attribute *item)
00160 {
00161 if (inv_spec.item || inv_spec.clsname)
00162 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00163 "inverse is already set for '%s'", name);
00164
00165 Status status = checkInverse();
00166 if (status)
00167 return status;
00168
00169 status = checkInverse(item);
00170 if (status)
00171 return status;
00172
00173 inv_spec.item = item;
00174 return Success;
00175 }
00176
00177 Status Attribute::setInverse(const char *clsname, const char *fname)
00178 {
00179 if (inv_spec.item || inv_spec.clsname)
00180 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00181 "inverse is already set for '%s'", name);
00182
00183 Status status = checkInverse();
00184 if (status)
00185 return status;
00186
00187 if (!clsname || !fname)
00188 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00189 "'%s' setInverse : invalid null value", name);
00190
00191 inv_spec.clsname = strdup(clsname);
00192 inv_spec.fname = strdup(fname);
00193 return Success;
00194 }
00195
00196 void
00197 Attribute::completeInverseItem(Schema *m)
00198 {
00199 if (!inv_spec.item->cls)
00200 ((Attribute *)inv_spec.item)->cls =
00201 m->getClass(inv_spec.item->oid_cl);
00202
00203 if (!inv_spec.item->class_owner)
00204 ((Attribute *)inv_spec.item)->class_owner =
00205 m->getClass(inv_spec.item->oid_cl_own);
00206 }
00207
00208 Status
00209 Attribute::completeInverse(Schema *m)
00210 {
00211 if (!inv_spec.clsname || inv_spec.item)
00212 return Success;
00213
00214 Class *cl;
00215 cl = m->getClass(inv_spec.clsname);
00216
00217 if (!cl)
00218 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00219 "attribute '%s' in agregat class '%s': "
00220 "cannot find agregat class '%s'",
00221 name, class_owner->getName(),
00222 inv_spec.clsname);
00223
00224 if (!cl->asAgregatClass())
00225 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00226 "attribute '%s' in agregat class '%s':"
00227 "class '%s' is not a agregat class",
00228 name, class_owner->getName(),
00229 inv_spec.clsname);
00230
00231 inv_spec.item = cl->getAttribute(inv_spec.fname);
00232
00233 if (!inv_spec.item)
00234 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
00235 "attribute '%s' in agregat class '%s': "
00236 "cannot find item '%s' in agregat class '%s'",
00237 name, class_owner->getName(),
00238 inv_spec.fname, inv_spec.clsname);
00239
00240 completeInverseItem(m);
00241
00242 return checkInverse(inv_spec.item);
00243 }
00244
00245 Status Attribute::completeInverse(Database *db)
00246 {
00247 Class *cl;
00248 Schema *m = db->getSchema();
00249
00250 Status s = completeInverse(m);
00251 if (s)
00252 return s;
00253
00254 if (inv_spec.item) {
00255 completeInverseItem(m);
00256
00257 inv_spec.num = inv_spec.item->num;
00258 cl = (Class *)inv_spec.item->class_owner;
00259
00260
00261 if (!cl)
00262 return Success;
00263
00264
00265 if (!cl->getOid().isValid()) {
00266 Status status = cl->create();
00267 if (status) return status;
00268 }
00269
00270 inv_spec.oid_cl = cl->getOid();
00271 }
00272
00273 return Success;
00274 }
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 static const char *
00299 get_op_name(Attribute::InvObjOp op)
00300 {
00301 if (op == Attribute::invObjCreate)
00302 return "ObjCreate";
00303
00304 if (op == Attribute::invObjUpdate)
00305 return "ObjUpdate";
00306
00307 if (op == Attribute::invObjRemove)
00308 return "ObjRemove";
00309
00310 return "invObjUnknown";
00311 }
00312
00313 Status
00314 Attribute::inverse_coll_perform(Database *db, InvObjOp op,
00315 const Oid &obj_oid,
00316 const Oid &inv_obj_oid) const
00317 {
00318
00319 if (!inv_spec.item)
00320 return Success;
00321
00322 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00323 ("inverse_coll_perform(%s, %s)\n", name, inv_spec.item->getName()));
00324
00325 if (inv_spec.item->getClass()->asCollectionClass())
00326 return inverse_coll_perform_N_N(db, op, obj_oid, inv_obj_oid);
00327
00328 return inverse_coll_perform_N_1(db, op, obj_oid, inv_obj_oid);
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 #define N_N_SIMPLE
00341
00342 Status
00343 Attribute::inverse_coll_perform_N_N(Database *db, InvObjOp op,
00344 const Oid &obj_oid,
00345 const Oid &x_obj_oid) const
00346 {
00347 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00348 ("inverse_coll_perform_N_N(%s, inv %s, op = %s, "
00349 "obj_oid = %s, x_obj_oid = %s)\n",
00350 name, inv_spec.item->getName(), get_op_name(op), obj_oid.toString(),
00351 x_obj_oid.toString()));
00352
00353 const Attribute *inv_item = inv_spec.item;
00354 InvCtx inv_ctx;
00355 assert(inv_item);
00356
00357 get_object_class(db, obj_oid);
00358 get_object_class(db, x_obj_oid);
00359
00360 if (op == invObjUpdate)
00361 {
00362 Oid old_obj_oid;
00363 CK(inverse_read_oid(db, inv_item, x_obj_oid, old_obj_oid));
00364
00365 Collection *coll = 0;
00366 if (old_obj_oid.isValid())
00367 CK(inverse_get_collection(db, old_obj_oid, coll));
00368
00369 #ifndef N_N_SIMPLE
00370 if (coll)
00371 {
00372 OidArray oid_arr;
00373 CK(coll->getElements(oid_arr));
00374
00375 for (int i = 0; i < oid_arr.getCount(); i++)
00376 {
00377 Oid coll_oid;
00378 CK(inverse_read_oid(db, this, oid_arr[i], coll_oid));
00379 if (coll_oid.isValid())
00380 {
00381 Collection *inv_coll;
00382 CK(inverse_get_collection(db, coll_oid, inv_coll));
00383 if (inv_coll)
00384 {
00385 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00386 ("suppressing [1] %s from collection %s\n",
00387 x_obj_oid.toString(),
00388 inv_coll->getOid().toString()));
00389 CK(inv_coll->suppress(x_obj_oid, True));
00390 CK(inverse_coll_realize(inv_coll));
00391 }
00392 }
00393 }
00394 }
00395 #endif
00396
00397 if (!coll)
00398 {
00399 CK(inverse_create_collection(db, inv_item, x_obj_oid,
00400 True, x_obj_oid, coll));
00401
00402 CK(inverse_write_oid(db, inv_item, x_obj_oid,
00403 coll->getOidC(), inv_ctx));
00404 }
00405
00406 #ifndef N_N_SIMPLE
00407 Collection *obj_coll = 0;
00408 Oid coll_obj_oid;
00409 CK(inverse_read_oid(db, this, obj_oid, coll_obj_oid));
00410
00411 CK(inverse_get_collection(db, coll_obj_oid, obj_coll));
00412
00413 OidArray oid_arr;
00414
00415 Iterator q(obj_coll);
00416 CK(q.getStatus());
00417 CK(q.scan(oid_arr));
00418
00419 obj_coll->release(); obj_coll = 0;
00420
00421 for (int i = 0; i < oid_arr.getCount(); i++)
00422 {
00423 Oid coll_oid;
00424 CK(inverse_read_oid(db, inv_item, oid_arr[i], coll_oid));
00425
00426 if (coll_oid.isValid())
00427 {
00428 Collection *inv_coll = 0;
00429 CK(inverse_get_collection(db, coll_oid, inv_coll));
00430 if (inv_coll)
00431 {
00432 OidArray inv_oid_arr;
00433 CK(inv_coll->getElements(inv_oid_arr));
00434 inv_coll->release(); inv_coll = 0;
00435
00436 for (int j = 0; j < inv_oid_arr.getCount(); j++)
00437 {
00438 Collection *rinv_coll = 0;
00439 Oid rinv_coll_oid;
00440 CK(inverse_read_oid(db, this, inv_oid_arr[j],
00441 rinv_coll_oid));
00442 if (rinv_coll_oid.isValid())
00443 {
00444 CK(inverse_get_collection(db, rinv_coll_oid,
00445 rinv_coll));
00446
00447 if (rinv_coll)
00448 {
00449 if (i == 0)
00450 {
00451 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00452 ("inserting [1] %s to collection %s\n",
00453 inv_oid_arr[j].toString(),
00454 coll->getOid().toString()));
00455 CK(coll->insert(inv_oid_arr[j], True));
00456 }
00457 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00458 ("appending [2] %s to collection %s\n",
00459 x_obj_oid.toString(),
00460 rinv_coll->getOid().toString()));
00461 CK(rinv_coll->insert(x_obj_oid, True));
00462 CK(inverse_coll_realize(rinv_coll));
00463 }
00464 }
00465 }
00466 }
00467 }
00468 }
00469 #endif
00470
00471 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00472 ("appending [3] %s to collection %s\n",
00473 obj_oid.toString(), coll->getOid().toString()));
00474 coll->insert(obj_oid, True);
00475 CK(inverse_coll_realize(coll));
00476
00477 return Success;
00478 }
00479
00480 if (op == invObjRemove)
00481 {
00482 Oid old_obj_oid;
00483 CK(inverse_read_oid(db, inv_item, x_obj_oid, old_obj_oid));
00484
00485 Collection *coll = 0;
00486 if (old_obj_oid.isValid())
00487 CK(inverse_get_collection(db, old_obj_oid, coll));
00488
00489 Oid cur_coll_oid;
00490 CK(inverse_read_oid(db, this, obj_oid, cur_coll_oid));
00491
00492 if (coll)
00493 {
00494 OidArray oid_arr;
00495 CK(coll->getElements(oid_arr));
00496
00497 for (int i = 0; i < oid_arr.getCount(); i++)
00498 {
00499 Oid coll_oid;
00500 CK(inverse_read_oid(db, this, oid_arr[i], coll_oid));
00501 if (coll_oid.isValid() && coll_oid != cur_coll_oid)
00502 {
00503 Collection *inv_coll;
00504 CK(inverse_get_collection(db, coll_oid, inv_coll));
00505 if (inv_coll)
00506 {
00507 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00508 ("suppressing [2] %s from collection %s\n",
00509 x_obj_oid.toString(),
00510 inv_coll->getOid().toString()));
00511 CK(inv_coll->suppress(x_obj_oid, True));
00512 CK(inverse_coll_realize(inv_coll));
00513 }
00514 }
00515 }
00516
00517 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00518 ("suppressing [3] %s from collection %s\n",
00519 obj_oid.toString(),
00520 coll->getOid().toString()));
00521 coll->suppress(obj_oid, True);
00522
00523 CK(inverse_coll_realize(coll));
00524 }
00525
00526 return Success;
00527 }
00528
00529 abort();
00530 return Success;
00531 }
00532
00533
00534
00535
00536
00537
00538
00539 Status
00540 Attribute::inverse_coll_perform_N_1(Database *db, InvObjOp op,
00541 const Oid &obj_oid,
00542 const Oid &x_obj_oid) const
00543 {
00544 IDB_LOG(IDB_LOG_RELSHIP_DETAILS, ("inverse_coll_perform_N_1(%s, inv %s, op = %s, "
00545 "obj_oid = %s, x_obj_oid = %s)\n",
00546 name, inv_spec.item->getName(), get_op_name(op), obj_oid.toString(),
00547 x_obj_oid.toString()));
00548
00549 const Attribute *inv_item = inv_spec.item;
00550 InvCtx inv_ctx;
00551 assert(inv_item);
00552
00553 get_object_class(db, obj_oid);
00554 get_object_class(db, x_obj_oid);
00555
00556 if (op == invObjUpdate)
00557 {
00558 Oid old_obj_oid;
00559 CK(inverse_read_oid(db, inv_item, x_obj_oid, old_obj_oid));
00560 if (old_obj_oid.isValid() && old_obj_oid != obj_oid)
00561 {
00562 Oid old_inv_obj_oid;
00563 CK(inverse_read_oid(db, this, old_obj_oid, old_inv_obj_oid));
00564 if (old_inv_obj_oid.isValid())
00565 {
00566 Collection *old_coll;
00567 CK(inverse_get_collection(db, old_inv_obj_oid, old_coll));
00568 if (old_coll)
00569 {
00570 OidArray oid_arr;
00571 CK(old_coll->getElements(oid_arr));
00572
00573 for (int i = 0; i < oid_arr.getCount(); i++)
00574 {
00575 CK(inverse_write_oid(db, inv_item, oid_arr[i],
00576 Oid::nullOid, inv_ctx));
00577 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00578 ("suppressing [4] %s from collection %s\n",
00579 oid_arr[i].toString(),
00580 old_coll->getOid().toString()));
00581 CK(old_coll->suppress(oid_arr[i], True));
00582 }
00583
00584 CK(inverse_coll_realize(old_coll));
00585 }
00586 }
00587 }
00588
00589 return inverse_write_oid(db, inv_item, x_obj_oid, obj_oid, inv_ctx);
00590 }
00591
00592 if (op == invObjRemove)
00593 return inverse_write_oid(db, inv_item, x_obj_oid, Oid::nullOid,
00594 inv_ctx);
00595
00596 abort();
00597 return Success;
00598 }
00599
00600 static void
00601 _trace_(const char *mth, Attribute::InvObjOp op,
00602 const Attribute *item,
00603 const Attribute *inv_item,
00604 const Oid &obj_oid,
00605 const Oid &inv_obj_oid)
00606 {
00607 if (!(IDB_LOG_RELSHIP_DETAILS & Log::getLogMask()))
00608 return;
00609
00610 char buf[256];
00611 std::string str;
00612 sprintf(buf, "Attribute::%s\n", mth);
00613 str += buf;
00614 sprintf(buf, "\t\top = %s;\n", get_op_name(op));
00615 str += buf;
00616 sprintf(buf, "\t\titem = %s, %d;\n", item->getName(), item->getNum());
00617 str += buf;
00618 sprintf(buf, "\t\tinv_item = %s, %d;\n", inv_item->getName(), inv_item->getNum());
00619 str += buf;
00620 sprintf(buf, "\t\tobj_oid = %s;\n", obj_oid.toString());
00621 str += buf;
00622 sprintf(buf, "\t\tinv_obj_oid = %s;\n\n", inv_obj_oid.toString());
00623 str += buf;
00624
00625 IDB_LOG(IDB_LOG_RELSHIP_DETAILS, (str.c_str()));
00626 }
00627
00628
00629
00630
00631
00632
00633
00634 Status
00635 Attribute::inverse_1_1(Database *db, InvObjOp op,
00636 const Attribute *inv_item,
00637 const Oid &obj_oid,
00638 const Oid &inv_obj_oid,
00639 const InvCtx &inv_ctx) const
00640 {
00641 _trace_("inverse_1_1", op, this, inv_item, obj_oid, inv_obj_oid);
00642
00643 if (op == invObjCreate)
00644 {
00645 if (!inv_obj_oid.isValid())
00646 return Success;
00647 Oid cur_obj_oid;
00648 CK(inverse_read_oid(db, inv_item, inv_obj_oid, cur_obj_oid));
00649
00650 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00651 ("inverse 1_1 create: cur_obj_oid %s\n",
00652 cur_obj_oid.toString()));
00653
00654 if (cur_obj_oid != obj_oid)
00655 {
00656 if (cur_obj_oid.isValid())
00657 CK(inverse_write_oid(db, this, cur_obj_oid, Oid::nullOid,
00658 inv_ctx));
00659 return inverse_write_oid(db, inv_item, inv_obj_oid, obj_oid,
00660 inv_ctx);
00661 }
00662
00663 return Success;
00664 }
00665
00666 if (op == invObjUpdate)
00667 {
00668 Oid old_inv_obj_oid;
00669 CK(inverse_read_oid(db, this, obj_oid, old_inv_obj_oid));
00670
00671 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00672 ("inverse 1_1 update: obj_oid %s, "
00673 "old_inv_obj_oid %s, inv_obj_oid %s\n",
00674 obj_oid.toString(), old_inv_obj_oid.toString(),
00675 inv_obj_oid.toString()));
00676
00677 if (old_inv_obj_oid.isValid() && old_inv_obj_oid != inv_obj_oid)
00678 {
00679 Oid old_obj_oid;
00680 CK(inverse_read_oid(db, inv_item, old_inv_obj_oid, old_obj_oid));
00681
00682 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00683 ("inverse 1_1 update: old_obj_oid %s\n", old_obj_oid.toString()));
00684 if (old_obj_oid == obj_oid)
00685 CK(inverse_write_oid(db, inv_item, old_inv_obj_oid,
00686 Oid::nullOid, inv_ctx));
00687 }
00688
00689 if (!inv_obj_oid.isValid())
00690 return Success;
00691
00692 Oid cur_obj_oid;
00693 CK(inverse_read_oid(db, inv_item, inv_obj_oid, cur_obj_oid));
00694
00695 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00696 ("inverse 1_1 update: cur_obj_oid %s\n",
00697 cur_obj_oid.toString()));
00698
00699
00700
00701 if (cur_obj_oid.isValid() && cur_obj_oid != obj_oid)
00702 CK(inverse_write_oid(db, this, cur_obj_oid, Oid::nullOid,
00703 inv_ctx));
00704 return inverse_write_oid(db, inv_item, inv_obj_oid, obj_oid, inv_ctx);
00705 }
00706
00707 if (op == invObjRemove)
00708 {
00709 if (!inv_obj_oid.isValid())
00710 return Success;
00711 return inverse_write_oid(db, inv_item, inv_obj_oid, Oid::nullOid,
00712 inv_ctx);
00713 }
00714
00715 abort();
00716 return Success;
00717 }
00718
00719
00720
00721
00722
00723
00724
00725 Status
00726 Attribute::inverse_1_N(Database *db, InvObjOp op,
00727 const Attribute *inv_item,
00728 const Oid &obj_oid,
00729 const Oid &inv_obj_oid,
00730 const InvCtx &inv_ctx) const
00731 {
00732 _trace_("inverse_1_N", op, this, inv_item, obj_oid, inv_obj_oid);
00733
00734 if (op == invObjUpdate)
00735 {
00736 Oid old_inv_obj_oid;
00737 CK(inverse_read_oid(db, this, obj_oid, old_inv_obj_oid));
00738
00739 if (old_inv_obj_oid.isValid() && old_inv_obj_oid != inv_obj_oid)
00740 {
00741 Oid old_obj_oid;
00742 CK(inverse_read_oid(db, inv_item, old_inv_obj_oid, old_obj_oid));
00743 if (old_obj_oid.isValid())
00744 {
00745 Collection *coll;
00746 CK(inverse_get_collection(db, old_obj_oid, coll));
00747
00748 if (coll)
00749 {
00750 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00751 ("suppressing [5] %s from collection %s\n",
00752 obj_oid.toString(),
00753 coll->getOid().toString()));
00754 CK(coll->suppress(obj_oid, True));
00755 CK(inverse_coll_realize(coll));
00756 }
00757 }
00758 }
00759 }
00760
00761 if (op == invObjCreate || op == invObjUpdate)
00762 {
00763 if (!inv_obj_oid.isValid())
00764 return Success;
00765
00766 Oid cur_obj_oid;
00767 CK(inverse_read_oid(db, inv_item, inv_obj_oid, cur_obj_oid));
00768
00769 Collection *coll = 0;
00770 if (cur_obj_oid.isValid())
00771 CK(inverse_get_collection(db, cur_obj_oid, coll));
00772
00773 if (!coll)
00774 {
00775 CK(inverse_create_collection(db, inv_item, Oid::nullOid,
00776 False, inv_obj_oid, coll));
00777 CK(inverse_write_oid(db, inv_item, inv_obj_oid, coll->getOidC(),
00778 inv_ctx));
00779 }
00780
00781 if (coll)
00782 {
00783 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00784 ("appending [4] %s to collection %s\n",
00785 obj_oid.toString(), coll->getOid().toString()));
00786 CK(coll->insert(obj_oid, True));
00787 CK(inverse_coll_realize(coll));
00788 }
00789
00790 return Success;
00791 }
00792
00793 if (op == invObjRemove)
00794 {
00795 if (!inv_obj_oid.isValid())
00796 return Success;
00797
00798 Oid cur_obj_oid;
00799 CK(inverse_read_oid(db, inv_item, inv_obj_oid, cur_obj_oid));
00800
00801 if (cur_obj_oid.isValid())
00802 {
00803 Collection *coll;
00804 CK(inverse_get_collection(db, cur_obj_oid, coll));
00805
00806 if (!coll)
00807 return Success;
00808
00809 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00810 ("suppressing [6] %s from collection %s\n",
00811 obj_oid.toString(),
00812 coll->getOid().toString()));
00813 CK(coll->suppress(obj_oid, True));
00814 CK(inverse_coll_realize(coll));
00815 return Success;
00816 }
00817
00818 return Success;
00819 }
00820
00821 abort();
00822 return Success;
00823 }
00824
00825
00826
00827
00828
00829
00830
00831 Status
00832 Attribute::inverse_N_1(Database *db, InvObjOp op,
00833 const Attribute *inv_item,
00834 const Oid &obj_oid,
00835 const Oid &inv_obj_oid,
00836 const InvCtx &inv_ctx) const
00837 {
00838 _trace_("inverse_N_1", op, this, inv_item, obj_oid, inv_obj_oid);
00839 Status status;
00840
00841 if (op == invObjUpdate)
00842 {
00843 Oid old_inv_obj_oid;
00844 CK(inverse_read_oid(db, this, obj_oid, old_inv_obj_oid));
00845 if (old_inv_obj_oid.isValid() && old_inv_obj_oid != inv_obj_oid)
00846 {
00847 Collection *old_coll = 0;
00848 CK(inverse_get_collection(db, old_inv_obj_oid, old_coll));
00849 if (old_coll)
00850 {
00851 OidArray oid_arr;
00852 CK(old_coll->getElements(oid_arr));
00853
00854 old_coll->release(); old_coll = 0;
00855
00856 for (int i = 0; i < oid_arr.getCount(); i++)
00857 CK(inverse_write_oid(db, inv_item, oid_arr[i],
00858 Oid::nullOid, inv_ctx));
00859 }
00860 }
00861 }
00862
00863 if (op == invObjCreate || op == invObjUpdate)
00864 {
00865 if (!inv_obj_oid.isValid()) return Success;
00866
00867 Collection *coll = 0;
00868 CK(inverse_get_collection(db, inv_obj_oid, coll));
00869
00870 if (coll)
00871 {
00872 OidArray oid_arr;
00873 CK(coll->getElements(oid_arr));
00874 coll->release(); coll = 0;
00875 for (int i = 0; i < oid_arr.getCount(); i++)
00876 {
00877 Oid old_obj_oid;
00878 CK(inverse_read_oid(db, inv_item, oid_arr[i], old_obj_oid));
00879 if (old_obj_oid != obj_oid)
00880 {
00881 if (old_obj_oid.isValid())
00882 CK(inverse_write_oid(db, this, old_obj_oid,
00883 Oid::nullOid, inv_ctx));
00884 CK(inverse_write_oid(db, inv_item, oid_arr[i], obj_oid,
00885 inv_ctx));
00886 }
00887 }
00888 }
00889
00890 return Success;
00891 }
00892
00893 if (op == invObjRemove)
00894 {
00895 if (!inv_obj_oid.isValid()) return Success;
00896
00897 Collection *coll;
00898
00899 CK(inverse_get_collection(db, inv_obj_oid, coll));
00900 if (coll)
00901 {
00902 OidArray oid_arr;
00903 CK(coll->getElements(oid_arr));
00904 coll->release(); coll = 0;
00905
00906 for (int i = 0; i < oid_arr.getCount(); i++)
00907 CK(inverse_write_oid(db, inv_item, oid_arr[i], Oid::nullOid,
00908 inv_ctx));
00909 }
00910
00911 return Success;
00912 }
00913
00914 abort();
00915 return Success;
00916
00917 return Success;
00918 }
00919
00920
00921
00922
00923
00924
00925
00926 Status
00927 Attribute::inverse_N_N(Database *db,
00928 InvObjOp op,
00929 const Attribute *inv_item,
00930 const Oid &obj_oid,
00931 const Oid &inv_obj_oid,
00932 const InvCtx &inv_ctx) const
00933 {
00934 _trace_("inverse_N_N", op, this, inv_item, obj_oid, inv_obj_oid);
00935
00936 if (op == invObjUpdate)
00937 {
00938 Oid old_inv_obj_oid;
00939 CK(inverse_read_oid(db, this, obj_oid, old_inv_obj_oid));
00940 if (old_inv_obj_oid.isValid() && old_inv_obj_oid != inv_obj_oid)
00941 {
00942 Collection *old_coll;
00943 CK(inverse_get_collection(db, old_inv_obj_oid, old_coll));
00944 if (old_coll)
00945 {
00946 OidArray oid_arr;
00947 CK(old_coll->getElements(oid_arr));
00948 for (int i = 0; i < oid_arr.getCount(); i++)
00949 {
00950 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00951 ("suppressing [7] %s from collection %s\n",
00952 oid_arr[i].toString(),
00953 old_coll->getOid().toString()));
00954 CK(old_coll->suppress(oid_arr[i], True));
00955
00956 Oid coll_oid;
00957 CK(inverse_read_oid(db, inv_item, oid_arr[i], coll_oid));
00958
00959 if (coll_oid.isValid())
00960 {
00961 Collection *inv_coll;
00962 CK(inverse_get_collection(db, coll_oid, inv_coll));
00963 if (inv_coll)
00964 {
00965 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
00966 ("suppressing [8] %s from collection %s\n",
00967 obj_oid.toString(),
00968 inv_coll->getOid().toString()));
00969 CK(inv_coll->suppress(obj_oid, True));
00970 CK(inverse_coll_realize(inv_coll));
00971 }
00972 }
00973 }
00974
00975 CK(inverse_coll_realize(old_coll));
00976 }
00977 }
00978
00979
00980 if ((old_inv_obj_oid.isValid() && old_inv_obj_oid == inv_obj_oid) ||
00981 !inv_obj_oid.isValid())
00982 return Success;
00983 }
00984
00985
00986
00987
00988
00989 if (op == invObjCreate || op == invObjUpdate)
00990 {
00991 if (!inv_obj_oid.isValid()) return Success;
00992
00993 Collection *coll;
00994 CK(inverse_get_collection(db, inv_obj_oid, coll));
00995
00996 if (!coll)
00997 return Success;
00998
00999 OidArray oid_arr;
01000 CK(coll->getElements(oid_arr));
01001
01002 for (int i = 0; i < oid_arr.getCount(); i++)
01003 {
01004 Oid coll_obj_oid;
01005 CK(inverse_read_oid(db, inv_item, oid_arr[i], coll_obj_oid));
01006 Collection *inv_coll = 0;
01007
01008 if (coll_obj_oid.isValid())
01009 CK(inverse_get_collection(db, coll_obj_oid, inv_coll));
01010
01011 if (!inv_coll)
01012 {
01013 CK(inverse_create_collection(db, inv_item, oid_arr[i],
01014 True, oid_arr[i], inv_coll));
01015
01016 CK(inverse_write_oid(db, inv_item, oid_arr[i],
01017 inv_coll->getOidC(), inv_ctx));
01018 }
01019
01020
01021
01022 IDB_LOG(IDB_LOG_RELSHIP_DETAILS, ("appending [5] %s to collection %s\n",
01023 obj_oid.toString(),
01024 inv_coll->getOid().toString()));
01025 CK(inv_coll->insert(obj_oid, True));
01026 CK(inverse_coll_realize(inv_coll));
01027 }
01028
01029
01030
01031 coll->release(); coll = 0;
01032 return Success;
01033 }
01034
01035 if (op == invObjRemove)
01036 {
01037 if (!inv_obj_oid.isValid()) return Success;
01038
01039 Collection *coll;
01040 CK(inverse_get_collection(db, inv_obj_oid, coll));
01041
01042 if (!coll)
01043 return Success;
01044
01045 OidArray oid_arr;
01046 CK(coll->getElements(oid_arr));
01047
01048 for (int i = 0; i < oid_arr.getCount(); i++)
01049 {
01050 Oid coll_oid;
01051 CK(inverse_read_oid(db, inv_item, oid_arr[i], coll_oid));
01052 if (coll_oid.isValid())
01053 {
01054 Collection *inv_coll;
01055 CK(inverse_get_collection(db, coll_oid, inv_coll));
01056 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
01057 ("suppressing [9] %s from collection %s\n",
01058 oid_arr[i].toString(),
01059 coll->getOid().toString()));
01060 CK(coll->suppress(oid_arr[i], True));
01061 if (inv_coll)
01062 {
01063 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
01064 ("suppressing [10] %s from collection %s\n",
01065 obj_oid.toString(),
01066 inv_coll->getOid().toString()));
01067 CK(inv_coll->suppress(obj_oid, True));
01068 CK(inverse_coll_realize(inv_coll));
01069 }
01070 }
01071 }
01072
01073 CK(inverse_coll_realize(coll));
01074 return Success;
01075 }
01076
01077 abort();
01078 return Success;
01079 }
01080
01081
01082
01083
01084
01085
01086
01087 Status
01088 Attribute::inverse_realize(Database *db, InvObjOp op, Data obj_idr,
01089 const Oid &obj_oid) const
01090 {
01091 if (!inv_spec.item) return Success;
01092
01093 InvCtx inv_ctx(obj_oid, obj_idr);
01094 const Attribute *inv_item = inv_spec.item;
01095 Oid inv_obj_oid = inverse_get_inv_obj_oid(obj_idr);
01096 Status status;
01097 Class *objcls = NULL;
01098
01099 IDB_LOG(IDB_LOG_RELSHIP, ("Attribute::inverse_realize(name = \"%s::%s\", "
01100 "invitem = \"%s::%s\", "
01101 "op = %s. obj_oid = %s, inv_obj_oid = %s)\n",
01102 class_owner->getName(), name,
01103 inv_item->getClassOwner()->getName(), inv_item->getName(),
01104 get_op_name(op),
01105 obj_oid.getString(), inv_obj_oid.getString()));
01106
01107 get_object_class(db, obj_oid);
01108 get_object_class(db, inv_obj_oid);
01109
01110 if (cls->asCollectionClass())
01111 {
01112 if (inv_item->cls->asCollectionClass())
01113 status = inverse_N_N(db, op, inv_item, obj_oid, inv_obj_oid, inv_ctx);
01114 else
01115 status = inverse_N_1(db, op, inv_item, obj_oid, inv_obj_oid, inv_ctx);
01116 }
01117 else
01118 {
01119 if (inv_item->cls->asCollectionClass())
01120 status = inverse_1_N(db, op, inv_item, obj_oid, inv_obj_oid, inv_ctx);
01121 else
01122 status = inverse_1_1(db, op, inv_item, obj_oid, inv_obj_oid, inv_ctx);
01123 }
01124
01125 IDB_LOG(IDB_LOG_RELSHIP,
01126 ("Attribute::inverse_realize(name = \"%s::%s\") ending with "
01127 "status '%s'\n\n", class_owner->getName(), name,
01128 (!status ? "success" : status->getDesc())));
01129
01130 return status;
01131 }
01132
01133
01134
01135
01136
01137
01138
01139 Status
01140 Attribute::createInverse_realize(Database *db,
01141 Data obj_idr,
01142 const Oid *obj_oid) const
01143 {
01144 return inverse_realize(db, invObjCreate, obj_idr, *obj_oid);
01145 }
01146
01147 Status
01148 Attribute::updateInverse_realize(Database *db,
01149 Data obj_idr,
01150 const Oid *obj_oid) const
01151 {
01152 return inverse_realize(db, invObjUpdate, obj_idr, *obj_oid);
01153 }
01154
01155 Status
01156 Attribute::removeInverse_realize(Database *db,
01157 Data obj_idr,
01158 const Oid *obj_oid) const
01159 {
01160 return inverse_realize(db, invObjRemove, obj_idr, *obj_oid);
01161 }
01162
01163
01164
01165
01166
01167
01168
01169 Status
01170 Attribute::inverse_get_collection(Database *db,
01171 const Oid &inv_obj_oid,
01172 Collection*& coll) const
01173 {
01174 coll = 0;
01175
01176 Object *o;
01177 Status status = db->loadObject(&inv_obj_oid, &o);
01178
01179 if (status)
01180 return status;
01181
01182 if (!o->asCollection())
01183 {
01184 o->release();
01185 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
01186 "%s::%s collection expected",
01187 class_owner->getName(), name);
01188 }
01189
01190 if (o->isRemoved())
01191 {
01192 o->release();
01193 return Success;
01194 }
01195
01196 coll = o->asCollection();
01197
01198 return Success;
01199 }
01200
01201 extern std::string
01202 getAttrCollDefName(const Attribute *attr, const Oid &oid);
01203
01204 Status
01205 Attribute::inverse_create_collection(Database *db,
01206 const Attribute *inv_item,
01207 const Oid &obj_oid,
01208 Bool is_N_N,
01209 const Oid &master_oid,
01210 Collection *&coll) const
01211 {
01212 Status status = requalify(db, master_oid, inv_item);
01213 if (status) return status;
01214
01215 if (!inv_item->isIndirect())
01216 {
01217 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
01218 ("creating literal collection '%s'\n", inv_item->getName()));
01219
01220 Object *master_obj=0;
01221 coll = 0;
01222 status = db->loadObject(master_oid, master_obj);
01223 if (status) return status;
01224 assert(master_obj);
01225 status = inv_item->getValue(master_obj, (Data *)&coll, 1, 0);
01226 if (status) return status;
01227 assert(coll);
01228 if (!coll->getOidC().isValid())
01229 {
01230 status = coll->create_realize(RecMode::NoRecurs);
01231 if (status) return status;
01232
01233 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
01234 ("have created literal collection %s for attribute %s::%s\n",
01235 coll->getOidC().toString(),
01236 inv_item->getClassOwner()->getName(),
01237 inv_item->getName()));
01238 }
01239 else
01240 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
01241 ("literal collection %s was already created "
01242 "for attribute %s::%s\n",
01243 coll->getOidC().toString(),
01244 inv_item->getClassOwner()->getName(),
01245 inv_item->getName()));
01246
01247 coll->incrRefCount();
01248 master_obj->release();
01249 return Success;
01250 }
01251
01252 std::string collname = getAttrCollDefName(inv_item, obj_oid);
01253
01254 Class *coll_class = const_cast<Class *>
01255 (inv_item->cls->asCollectionClass()->getCollClass());
01256
01257 if (inv_item->cls->asCollSetClass())
01258 coll = new CollSet(db, collname.c_str(), coll_class);
01259
01260 else if (inv_item->cls->asCollBagClass()) {
01261
01262 coll = new CollBag(db, collname.c_str(), coll_class);
01263 }
01264
01265 else if (inv_item->cls->asCollArrayClass())
01266 coll = new CollArray(db, collname.c_str(), coll_class);
01267
01268 else if (inv_item->cls->asCollListClass())
01269 coll = new CollList(db, collname.c_str(), coll_class);
01270
01271 else {
01272 coll = 0;
01273 abort();
01274 }
01275
01276 if (is_N_N)
01277 CollectionPeer::setInvOid(coll, obj_oid, inv_item->getNum());
01278
01279 IDB_LOG(IDB_LOG_RELSHIP_DETAILS, ("creating collection '%s' "
01280 "-> magorder %u\n",
01281 inv_item->getName(),
01282 inv_item->getMagOrder()));
01283
01284
01285
01286
01287 status = coll->realize();
01288
01289
01290 IDB_LOG(IDB_LOG_RELSHIP_DETAILS, ("have created collection %s for "
01291 "attribute %s::%s\n",
01292 coll->getOid().toString(),
01293 inv_item->getClassOwner()->getName(),
01294 inv_item->getName()));
01295
01296 if (is_N_N)
01297 IDB_LOG(IDB_LOG_RELSHIP_DETAILS,
01298 ("setting inv_oid %s to collection %s\n",
01299 obj_oid.toString(), coll->getOidC().toString()));
01300
01301 return status;
01302 }
01303
01304 Oid
01305 Attribute::inverse_get_inv_obj_oid(Data obj_idr) const
01306 {
01307 Oid inv_obj_oid;
01308 eyedbsm::x2h_oid(inv_obj_oid.getOid(), obj_idr + idr_poff);
01309 return inv_obj_oid;
01310 }
01311
01312 Status
01313 Attribute::inverse_read_oid(Database *db, const Attribute *item,
01314 const Oid &obj_oid,
01315 Oid &old_obj_oid)
01316 {
01317 if (obj_oid.getDbid() != db->getDbid())
01318 return Exception::make(IDB_ATTRIBUTE_INVERSE_ERROR,
01319 "%s does not belong to database #%d: relationships cannot cross databases", obj_oid.toString(), db->getDbid());
01320
01321 eyedbsm::Oid toid;
01322 Status s = StatusMake(dataRead(db->getDbHandle(), item->idr_poff,
01323 sizeof(eyedbsm::Oid),
01324 (Data)&toid, 0,
01325 obj_oid.getOid()));
01326 eyedbsm::x2h_oid(old_obj_oid.getOid(), &toid);
01327
01328 IDB_LOG(IDB_LOG_RELSHIP_DETAILS, ("read oid -> item=%s, obj_oid=%s, "
01329 "old_obj_oid=%s\n",
01330 item->getName(), obj_oid.toString(),
01331 old_obj_oid.toString()));
01332 return s;
01333 }
01334
01335
01336 Status
01337 Attribute::inverse_write_oid(Database *db, const Attribute *item,
01338 const Oid &obj_oid,
01339 const Oid &new_obj_oid,
01340 const InvCtx &inv_ctx)
01341 {
01342
01343
01344 if (item->isIndirect()) {
01345 Status status = item->updateIndexForInverse(db, obj_oid, new_obj_oid);
01346 if (status)
01347 return status;
01348 }
01349
01350 IDB_LOG(IDB_LOG_RELSHIP_DETAILS, ("write oid -> item=%s, obj_oid=%s, "
01351 "new_obj_oid=%s\n",
01352 item->getName(), obj_oid.toString(),
01353 new_obj_oid.toString()));
01354
01355 InvOidContext::insert(obj_oid, item, new_obj_oid);
01356
01357 eyedbsm::Oid toid;
01358 eyedbsm::h2x_oid(&toid, new_obj_oid.getOid());
01359
01360 if (obj_oid == inv_ctx.oid) {
01361
01362
01363
01364 mcp(inv_ctx.idr+item->idr_poff, &toid, sizeof(Oid));
01365 }
01366
01367 return StatusMake(dataWrite(db->getDbHandle(), item->idr_poff,
01368 sizeof(eyedbsm::Oid),
01369 (Data)&toid,
01370 obj_oid.getOid()));
01371 }
01372 }