odl_update.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 #define protected public
00026 #include "odl.h"
00027 #include "misc.h"
00028 #include "eyedb/internals/ClassPeer.h"
00029 #include "eyedb/internals/ObjectPeer.h"
00030 //#include "imdl.h"
00031 #include "oql_p.h"
00032 #include "CollectionBE.h"
00033 #include <sstream>
00034 using std::ostringstream;
00035 
00036 //#define TRACE
00037 
00038 using namespace std;
00039 
00040 namespace eyedb {
00041 
00042 extern FILE *odl_fd;
00043 #define SHBE " must "
00044 
00045 class odlPostUpdate {
00046   static LinkedList list;
00047   Oid oclsoid;
00048   Class *cls;
00049 
00050   odlPostUpdate(const Oid &_oclsoid, Class *_cls) {
00051     oclsoid = _oclsoid;
00052     cls = _cls;
00053   }
00054 
00055   Status perform(Database *db);
00056 
00057 public:
00058   static void add(const Oid &oclsoid, Class *cls);
00059   static Status realize(Database *db);
00060 };
00061 
00062 LinkedList odlPostUpdate::list;
00063 
00064 //
00065 // odlUpdateItem methods
00066 //
00067 
00068 void
00069 odlUpdateItem::initDisplay()
00070 {
00071   static int init;
00072 
00073   if (!init)
00074     {
00075       fprintf(odl_fd, "\n");
00076       init = 1;
00077     }
00078 }
00079 
00080 void
00081 odlUpdateItem::initDisplayDiff(Database *_db, const char *_odlfile)
00082 {
00083   static Database *db;
00084   static const char *odlfile;
00085   static int init;
00086 
00087   if (_db)
00088     {
00089       db = _db;
00090       odlfile = _odlfile;
00091       return;
00092     }
00093 
00094   if (!init)
00095     {
00096       fprintf(odl_fd, "\nDifferences between database '%s' and '%s':\n\n",
00097               db->getName(), odlfile);
00098       init = 1;
00099     }
00100 }
00101 
00102 //
00103 // update component method family
00104 //
00105 
00106 void
00107 odlUpdateComponent::realize(Database *db, Schema *m)
00108 {
00109   if (cls_comp) {
00110     cls_comp->setDatabase(db);
00111     cls_comp->setClassOwner(m->getClass(cls_comp->getClassOwner()->getName()));
00112 
00113     Class *clown = cls_comp->getClassOwner();
00114     if (!clown->getIDR() && clown->getUserData())
00115       ObjectPeer::setIDR(clown,
00116                             ((Class *)clown->getUserData())->getIDR());
00117     cls_comp->setClassOwnerOid(cls_comp->getClassOwner()->getOid());
00118   }
00119   else {
00120     attr_comp->setDatabase(db);
00121   }
00122 }
00123 
00124 Status
00125 odlRemoveComponent::prePerform(Database *db, Schema *m)
00126 {
00127   return Success;
00128 }
00129 
00130 odlAddComponent::odlAddComponent(ClassComponent *_comp) :
00131   odlUpdateComponent(_comp)
00132 {
00133 #ifdef TRACE
00134   printf("AddComponent(%p)\n", this);
00135   printf("AddComponent(%p)\n", this);
00136   printf("%s '", cls_comp->getClass()->getCanonicalName());
00137   cls_comp->m_trace(stdout, 0, 0, NoRecurs);
00138   printf("\n");
00139 #endif
00140 }
00141 
00142 odlAddComponent::odlAddComponent(AttributeComponent *_attr_comp) :
00143   odlUpdateComponent(_attr_comp)
00144 {
00145 #ifdef TRACE
00146   printf("AddComponent(%p)\n", this);
00147   printf("%s '", attr_comp->getClassOwner()->getCanonicalName());
00148   comp->m_trace(stdout, 0, AttrCompDetailTrace, NoRecurs);
00149   printf("\n");
00150 #endif
00151 }
00152 
00153 Status
00154 odlAddComponent::postPerform(Database *db, Schema *m)
00155 {
00156   realize(db, m);
00157   display();
00158 
00159 #ifdef TRACE
00160   printf("realizing component %p %s %s addcomponent::postPerform\n", comp,
00161          cls_comp->getName(), cls_comp->getOid().toString());
00162 #endif
00163   if (cls_comp)
00164     return cls_comp->realize_for_update();
00165   return attr_comp->realize();
00166 }
00167 
00168 odlRemoveComponent::odlRemoveComponent(ClassComponent *_cls_comp) :
00169   odlUpdateComponent(_cls_comp)
00170 {
00171 #ifdef TRACE
00172   printf("RemoveComponent(%p)\n", this);
00173   printf("%s '", cls_comp->getClass()->getCanonicalName());
00174   comp->m_trace(stdout, 0, 0, NoRecurs);
00175   printf("\n");
00176 #endif
00177 }
00178 
00179 odlRemoveComponent::odlRemoveComponent(AttributeComponent *_attr_comp) :
00180   odlUpdateComponent(_attr_comp)
00181 {
00182 #ifdef TRACE
00183   printf("RemoveComponent(%p)\n", this);
00184   printf("%s '", attr_comp->getClassOwner()->getCanonicalName());
00185   comp->m_trace(stdout, 0, AttrCompDetailTrace, NoRecurs);
00186   printf("\n");
00187 #endif
00188 }
00189 
00190 Status
00191 odlRemoveComponent::postPerform(Database *db, Schema *m)
00192 {
00193   if (cls_comp && cls_comp->isRemoved())
00194     return Success;
00195 
00196   if (attr_comp && attr_comp->isRemoved())
00197     return Success;
00198 
00199   realize(db, m);
00200   display();
00201 
00202   if (cls_comp)
00203     return cls_comp->remove_for_update();
00204 
00205   return attr_comp->remove();
00206 }
00207 
00208 void
00209 odlUpdateComponent::display()
00210 {
00211   odlUpdateItem::initDisplay();
00212 
00213   //printf("attr_comp = %p\n", attr_comp);
00214 
00215   if (asRemoveComponent())
00216     fprintf(odl_fd, "Removing ");
00217   /*
00218   else if ((cls_comp && cls_comp->getOid().isValid()) ||
00219            (attr_comp && attr_comp->getOid().isValid()))
00220   */
00221   else if (updating)
00222     fprintf(odl_fd, "Updating ");
00223   else
00224     fprintf(odl_fd, "Creating ");
00225 
00226   if (cls_comp) {
00227     //fprintf(odl_fd, "[%s] ", cls_comp->getOid().toString());
00228     fprintf(odl_fd, "%s '", cls_comp->getClass()->getCanonicalName());
00229     cls_comp->m_trace(odl_fd, 0, 0, NoRecurs);
00230   }
00231   else {
00232     //fprintf(odl_fd, "[%s] ", attr_comp->getOid().toString());
00233     fprintf(odl_fd, "%s '", attr_comp->getClass()->getCanonicalName());
00234     attr_comp->m_trace(odl_fd, 0, AttrCompDetailTrace, NoRecurs);
00235   }
00236 
00237   if (asRemoveComponent())
00238     fprintf(odl_fd, "' from ");
00239   else
00240     fprintf(odl_fd, "' on ");
00241   
00242   fprintf(odl_fd, "class '%s'...\n", (cls_comp ? cls_comp->getClassOwner()->getName() : attr_comp->getClassOwner()->getName()));
00243 }
00244 
00245 void
00246 odlUpdateComponent::displayDiff(Database *db, const char *odlfile)
00247 {
00248   odlUpdateItem::initDisplayDiff(db, odlfile);
00249 
00250   if (cls_comp) {
00251     fprintf(odl_fd, "  class %s: ", cls_comp->getClassOwner()->getName());
00252     cls_comp->m_trace(odl_fd, 0, 0, NoRecurs);
00253   } else {
00254     fprintf(odl_fd, "  class %s: ", attr_comp->getClassOwner()->getName());
00255     attr_comp->m_trace(odl_fd, 0, AttrCompDetailTrace, NoRecurs);
00256   }
00257 
00258   fprintf(odl_fd, SHBE);
00259   if (asAddComponent())
00260     fprintf(odl_fd, "be added to database");
00261   else
00262     fprintf(odl_fd, "be removed from database");
00263 
00264   fprintf(odl_fd, "\n");
00265 }
00266 
00267 //
00268 // update class method family
00269 //
00270 
00271 Status
00272 odlAddClass::prePerform(Database *db, Schema *m)
00273 {
00274   display();
00275   return Success;
00276 }
00277 
00278 bool must_remove(const Class *cls, const Oid &cls_oid, bool check_self)
00279 {
00280   if (check_self && cls->getOid() == cls_oid)
00281     return true;
00282 
00283   if (cls->asCollectionClass()) {
00284     const Class *coll_class = cls->asCollectionClass()->getCollClass();
00285     if (coll_class->getOid() == cls_oid)
00286       return true;
00287 
00288     return false;
00289   }
00290 
00291   if (cls->getParent() && cls->getParent()->getOid() == cls_oid)
00292     return true;
00293 
00294   return false;
00295 }
00296 
00297 odlRemoveClass::odlRemoveClass(Database *db, const Class *_cls,
00298                                LinkedList *list) :
00299   odlUpdateClass(_cls), list(list)
00300 {
00301   Oid cls_oid = cls->getOid();
00302 }
00303 
00304 Status
00305 odlRemoveClass::prePerform(Database *db, Schema *_m)
00306 {
00307   Oid cls_oid = cls->getOid();
00308 
00309   const Schema *m = db->getSchema();
00310   const LinkedList *cls_lst = m->getClassList();
00311   LinkedListCursor c(cls_lst);
00312   Class *xcls;
00313 
00314   string err;
00315 
00316   while (c.getNext((void *&)xcls)) {
00317     if (must_remove(xcls, cls_oid, false))
00318       err += string("\n  must remove class ") + xcls->getName();
00319     else {
00320       unsigned int attr_cnt;
00321       const Attribute **attrs = xcls->getAttributes(attr_cnt);
00322       for (int n = 0; n < attr_cnt; n++) {
00323         if (must_remove(attrs[n]->getClass(), cls_oid, true))
00324           err += string("\n  must remove class ") + xcls->getName() +
00325             " or remove attribute " + attrs[n]->getClassOwner()->getName() +
00326             "::" + attrs[n]->getName();
00327       }
00328     }
00329   }
00330 
00331   if (err.size())
00332     return Exception::make((string("while removing class ") + cls->getName() + ": " +
00333                             err).c_str());
00334 
00335   return Success;
00336 }
00337 
00338 Status
00339 odlRemoveClass::postPerform(Database *db, Schema *m)
00340 {
00341   display();
00342 
00343   const Class *ocls = (const Class *)cls->getUserData();
00344 
00345   if (!ocls->isRemoved() && ocls->getOid().isValid()) {
00346     Status s = const_cast<Class *>(ocls)->remove_r
00347       (RecMode::NoRecurs, Class::RemoveInstances);
00348     if (s) return s;
00349   }
00350 
00351   return Success;
00352 }
00353 
00354 Status
00355 odlRenameClass::prePerform(Database *db, Schema *m)
00356 {
00357   return Success;
00358 }
00359 
00360 Status
00361 odlReparentClass::prePerform(Database *db, Schema *m)
00362 {
00363   return Success;
00364 }
00365 
00366 Status
00367 odlConvertClass::prePerform(Database *db, Schema *m)
00368 {
00369   return Success;
00370 }
00371 
00372 void
00373 odlUpdateClass::display()
00374 {
00375   odlUpdateItem::initDisplay();
00376 
00377   if (asRemoveClass())
00378     fprintf(odl_fd, "Removing");
00379   else if (asAddClass())
00380     fprintf(odl_fd, "Adding");
00381   else if (asConvertClass())
00382     fprintf(odl_fd, "Converting");
00383   else if (asReparentClass())
00384     fprintf(odl_fd, "Reparenting");
00385   else if (asRenameClass())
00386     fprintf(odl_fd, "Renaming");
00387 
00388   fprintf(odl_fd, " class %s", cls->getName());
00389   if (asRenameClass())
00390     fprintf(odl_fd, " from %s", asRenameClass()->name);
00391   fprintf(odl_fd, "\n");
00392 }
00393 
00394 void
00395 odlUpdateClass::displayDiff(Database *db, const char *odlfile)
00396 {
00397   odlUpdateItem::initDisplayDiff(db, odlfile);
00398 
00399   fprintf(odl_fd, "  class %s:" SHBE, cls->getName());
00400 
00401   if (asRemoveClass())
00402     fprintf(odl_fd, "be removed from database");
00403   else if (asAddClass())
00404     fprintf(odl_fd, "be added to database");
00405   else if (asConvertClass())
00406     fprintf(odl_fd, "be converted");
00407   else if (asReparentClass())
00408     fprintf(odl_fd, "be reparented to %s", cls->getParent()->getName());
00409   else if (asRenameClass())
00410     fprintf(odl_fd, "be renamed from %s", asRenameClass()->name);
00411 
00412   fprintf(odl_fd, "\n");
00413 }
00414 
00415 Status
00416 odlUpdateClass::postPerform(Database *db, Schema *m)
00417 {
00418   if (!clsconv)
00419     return Success;
00420 
00421   clsconv->setOidN(cls->getOid());
00422   return clsconv->realize();
00423 }
00424 
00425 //
00426 // update relationship method family
00427 //
00428 
00429 Status
00430 odlAddRelationship::postPerform(Database *db, Schema *m)
00431 {
00432   display();
00433   return Success;
00434 }
00435 
00436 Status
00437 odlRemoveRelationship::postPerform(Database *db, Schema *m)
00438 {
00439   display();
00440   return Success;
00441 }
00442 
00443 static const char *
00444 get_relship_card(const Attribute *item, const Attribute *invitem)
00445 {
00446   if (item->getClass()->asCollectionClass())
00447     {
00448       if (invitem->getClass()->asCollectionClass())
00449         return "many-to-many";
00450       return "many-to-one";
00451     }
00452 
00453   if (invitem->getClass()->asCollectionClass())
00454     return "one-to-many";
00455   return "one-to-one";
00456 }
00457 
00458 void
00459 odlUpdateRelationship::display()
00460 {
00461   odlUpdateItem::initDisplay();
00462 
00463   //fprintf(odl_fd, "class %s: ", item->getClassOwner()->getName());
00464 
00465   if (asRemoveRelationship())
00466     fprintf(odl_fd, "Removing ");
00467   else
00468     fprintf(odl_fd, "Creating ");
00469 
00470   fprintf(odl_fd, "%s relationship %s::%s <-> %s::%s\n",
00471           get_relship_card(item, invitem),
00472           item->getClassOwner()->getName(), item->getName(),
00473           invitem->getClassOwner()->getName(),
00474           invitem->getName());
00475 }
00476 
00477 void
00478 odlUpdateRelationship::displayDiff(Database *db, const char *odlfile)
00479 {
00480   odlUpdateItem::initDisplayDiff(db, odlfile);
00481 
00482   fprintf(odl_fd, "  class %s: ", item->getClassOwner()->getName());
00483   fprintf(odl_fd, "%s relationship %s::%s <-> %s::%s",
00484           get_relship_card(item, invitem),
00485           item->getClassOwner()->getName(), item->getName(),
00486           invitem->getClassOwner()->getName(),
00487           invitem->getName());
00488   
00489   fprintf(odl_fd, SHBE);
00490   if (asAddRelationship())
00491     fprintf(odl_fd, "be added to database");
00492   else
00493     fprintf(odl_fd, "be removed from database");
00494 
00495   fprintf(odl_fd, "\n");
00496 }
00497 
00498 //
00499 // update attribute method family
00500 //
00501 
00502 void
00503 odlUpdateAttribute::display()
00504 {
00505   odlUpdateItem::initDisplay();
00506 
00507   if (asAddAttribute())
00508     fprintf(odl_fd, "Adding");
00509   else if (asRemoveAttribute())
00510     fprintf(odl_fd, "Removing");
00511 
00512   fprintf(odl_fd, " attribute %s::%s", cls->getName(), item->getName());
00513 
00514   fprintf(odl_fd, "\n");
00515 }
00516 
00517 void
00518 odlUpdateAttribute::displayDiff(Database *db, const char *odlfile)
00519 {
00520   odlUpdateItem::initDisplayDiff(db, odlfile);
00521 
00522   fprintf(odl_fd, "  class %s: attribute %s", cls->getName(), item->getName());
00523   
00524   fprintf(odl_fd, SHBE);
00525   if (asAddAttribute())
00526     fprintf(odl_fd, "be added to database");
00527   else if (asRemoveAttribute())
00528     fprintf(odl_fd, "be removed from database");
00529 
00530   fprintf(odl_fd, "\n");
00531 }
00532 
00533 Status
00534 odlUpdateAttribute::invalidateCollClassOid(Database *db,
00535                                            const Class *ocls)
00536 {
00537   const LinkedList *list = db->getSchema()->getClassList();
00538   LinkedListCursor c(list);
00539   Class *xcls;
00540   while (c.getNext((void *&)xcls))
00541     {
00542       CollectionClass *cls_c = xcls->asCollectionClass();
00543       if (!cls_c)
00544         continue;
00545       if (cls_c->getCollClass()->getOid() == ocls->getOid())
00546         cls_c->invalidateCollClassOid();
00547     }
00548 
00549   return Success;
00550 }
00551 
00552 Status
00553 odlUpdateAttribute::invalidateInverseOid(Database *db,
00554                                          const Class *ocls)
00555 {
00556   const LinkedList *list = db->getSchema()->getClassList();
00557   LinkedListCursor c(list);
00558   Class *xcls;
00559   while (c.getNext((void *&)xcls))
00560     {
00561       AgregatClass *cls_c = xcls->asAgregatClass();
00562       if (!cls_c || cls_c->isSystem())
00563         continue;
00564       unsigned int attr_cnt;
00565       const Attribute **attrs = cls_c->getAttributes(attr_cnt);
00566       for (int i = 0; i < attr_cnt; i++)
00567         {
00568           const char *clsname = 0;
00569           attrs[i]->getInverse(&clsname, 0, 0);
00570           if (clsname && !strcmp(clsname, ocls->getName()))
00571             {
00572               xcls->touch();
00573               break;
00574             }
00575         }
00576     }
00577 
00578   return Success;
00579 }
00580 
00581 Status
00582 odlUpdateAttribute::reportExtentOid(Database *db, const Class *ocls)
00583 {
00584   Collection *extent = 0, *cls_comp;
00585   Status s = ocls->getExtent(extent);
00586   if (s) return s;
00587   s = ocls->getComponents(cls_comp);
00588   if (s) return s;
00589   const_cast<Class *>(cls)->setExtentCompOid(extent->getOid(),
00590                                                 cls_comp->getOid());
00591   return Success;
00592 }
00593 
00594 static Bool
00595 odlIsInSchema(Database *db, const Class *scls)
00596 {
00597   Schema *m = db->getSchema();
00598   const LinkedList *list = m->getClassList();
00599   LinkedListCursor c(list);
00600   
00601   Class *cls;
00602   while (c.getNext((void *&)cls))
00603     if (cls == scls)
00604       return True;
00605 
00606   return False;
00607 }
00608 
00609 Status
00610 odlUpdateAttribute::check()
00611 {
00612   if (!odlAgregatClass::getDeclaredCount())
00613     return Success;
00614 
00615   std::string s = "when the schema is evolving all database user classes "
00616     "must be defined in the odl file:\nmissing ";
00617   LinkedList &list = odlAgregatClass::getDeclaredList();
00618   LinkedListCursor c(list);
00619   char *name;
00620   for (int i = 0; c.getNext((void *&)name); i++)
00621     s += std::string(i ? ", " : "") + name;
00622   s += std::string(" class definition") + (list.getCount() > 1 ? "s" : "");
00623   return Exception::make(IDB_ERROR, s);
00624 }
00625 
00626 static Bool
00627 is_defined(const Class *cls)
00628 {
00629   LinkedList &list = odlAgregatClass::getDeclaredList();
00630   LinkedListCursor c(list);
00631   char *name;
00632 
00633   while (c.getNext((void *&)name))
00634     if (!strcmp(name, cls->getName()))
00635       return False;
00636 
00637   return True;
00638 }
00639 
00640 static Bool
00641 refer_to(const Attribute *attr, const Class *cls);
00642 
00643 static Bool
00644 refer_to(const Class *xcls, const Class *cls)
00645 {
00646   if (xcls->state)
00647     return False;
00648 
00649   const_cast<Class *>(xcls)->state |= 1;
00650 
00651   unsigned int attr_cnt;
00652   const Attribute **attrs = xcls->getAttributes(attr_cnt);
00653   for (int i = 0; i < attr_cnt; i++)
00654     if (refer_to(attrs[i], cls)) {
00655       const_cast<Class *>(xcls)->state &= ~1;
00656       return True;
00657     }
00658 
00659   const_cast<Class *>(xcls)->state &= ~1;
00660   return False;
00661 }
00662 
00663 static Bool
00664 refer_to(const Attribute *attr, const Class *cls)
00665 {
00666   const Class *attr_cls = attr->getClass();
00667   assert(attr_cls);
00668 
00669   if (attr_cls->asBasicClass() ||
00670       attr_cls->asEnumClass() || attr_cls->asCollectionClass())
00671     return False;
00672 
00673   //  if (attr_cls->compare(cls))
00674   if (!strcmp(attr_cls->getName(), cls->getName()))
00675     return True;
00676 
00677   return refer_to(attr_cls, cls);
00678 }
00679 
00680 Status
00681 odlUpdateAttribute::check(Database *db, const Class *cls)
00682 {
00683   if (!odlAgregatClass::getDeclaredCount())
00684     return Success;
00685 
00686   LinkedListCursor c(db->getSchema()->getClassList());
00687   Class *xcls;
00688   std::string s = "when the schema is evolving all database user classes "
00689     "referring to an evolving classes "
00690     "must be defined in the odl file:\n";
00691 
00692   int n = 0;
00693   while (c.getNext((void *&)xcls))
00694     if (refer_to(xcls, cls) && !is_defined(xcls)) {
00695       s += std::string("class ") + xcls->getName() + " refers to class " +
00696         cls->getName() + " and definition is missing\n";
00697       n++;
00698     }
00699 
00700   if (!n)
00701     return Success;
00702 
00703   return Exception::make(IDB_ERROR, s);
00704 }
00705 
00706 //#undef TRACE
00707 
00708 //
00709 // odlPostUpdate methods
00710 //
00711 
00712 Status
00713 odlPostUpdate::perform(Database *db)
00714 {
00715   Collection *components;
00716   Status s = cls->getComponents(components, True);
00717   if (s) return s;
00718 
00719   Iterator c(components);
00720 
00721 #ifdef TRACE
00722   printf("REALIZING %s %s\n", cls->getName(), oclsoid.toString());
00723 #endif
00724   ClassComponent *cls_comp;
00725   for (;;) {
00726     Bool found;
00727     s = c.scanNext(found, (Object *&)cls_comp);
00728     if (s) return s;
00729     if (!found) break;
00730     if (cls_comp->getClassOwner()->getOid() == oclsoid) {
00731 #ifdef TRACE
00732       printf("changing class owner for %s\n", cls_comp->getName());
00733 #endif
00734       cls_comp->setClassOwner(cls);
00735       s = cls_comp->realize();
00736       if (s) return s;
00737     }
00738   }
00739 
00740   unsigned int attr_cnt;
00741   Attribute **attrs = (Attribute **)cls->getAttributes(attr_cnt);
00742 
00743   return Success;
00744 }
00745 
00746 Status
00747 odlPostUpdate::realize(Database *db)
00748 {
00749   LinkedListCursor c(list);
00750   odlPostUpdate *p;
00751   while (c.getNext((void *&)p)) {
00752     Status s = p->perform(db);
00753     if (s) return s;
00754   }
00755   return Success;
00756 }
00757 
00758 void
00759 odlPostUpdate::add(const Oid &oclsoid, Class *cls)
00760 {
00761   list.insertObjectLast(new odlPostUpdate(oclsoid, (Class *)cls));
00762 }
00763 
00764 Status
00765 odl_post_update(Database *db)
00766 {
00767   return odlPostUpdate::realize(db);
00768 }
00769 
00770 static void
00771 odl_components_manage(const Class *cls, const Class *ocls)
00772 {
00773   ClassComponent *cls_comp;
00774   LinkedListCursor c(cls->getCompList());
00775 
00776 #ifdef TRACE
00777   printf("Components of new class %s %s\n", cls->getName(), cls->getOid().toString());
00778 #endif
00779   while (c.getNext((void *&)cls_comp)) {
00780 #ifdef TRACE
00781     printf("\t%s %s\n", cls_comp->getOid().toString(), cls_comp->getName());
00782 #endif
00783     if (!cls_comp->getOid().isValid()) {
00784       // cls->getCompList()->deleteObject(comp);
00785       LinkedListCursor oc(ocls->getCompList());
00786       ClassComponent *ocls_comp;
00787       const char *cname = cls_comp->getName().c_str();
00788       while (oc.getNext((void *&)ocls_comp)) {
00789         if (!strcmp(cname, ocls_comp->getName().c_str())) {
00790           ObjectPeer::setOid(cls_comp, ocls_comp->getOid());
00791 #ifdef TRACE
00792           printf("\tsetting %p %s to %s [%s vs. %s %p %p]\n", comp, ocls_comp->getOid().toString(), cls_comp->getName(), cls_comp->getClassOwner()->getOid().toString(),
00793                  ocls_comp->getClassOwner()->getOid().toString(),
00794                  cls_comp->getClassOwner(), ocls_comp->getClassOwner());
00795 #endif
00796           break;
00797         }
00798       }
00799 #ifdef TRACE
00800       if (!cls_comp->getOid().isValid()) {
00801         printf("WARNING %s has no oid\n", cls_comp->getName());
00802       }
00803 #endif
00804     }
00805 
00806     /*
00807     printf("touching component %p %s\n", comp, cls_comp->getOid().toString());
00808     cls_comp->touch();
00809     */
00810   }
00811 
00812   const_cast<LinkedList *>(cls->getCompList())->empty();
00813   const_cast<Class *>(cls)->setUserData("eyedb:odl::update", AnyUserData);
00814 
00815 #ifdef TRACE
00816   printf("Components of old class %s %s\n", ocls->getName(), ocls->getOid().toString());
00817 
00818   LinkedListCursor oc(ocls->getCompList());
00819   while (oc.getNext((void *&)comp)) {
00820     printf("\t%s %s\n", cls_comp->getOid().toString(), cls_comp->getName());
00821   }
00822 #endif
00823 }
00824 
00825 Status
00826 odlUpdateAttribute::initClassConv(Database *db)
00827 {
00828   Status s = check(db, cls);
00829   if (s) return s;
00830 
00831   clsconv = new ClassConversion(db);
00832 
00833   const Class *ocls = (const Class *)cls->getUserData();
00834   assert(ocls);
00835   odl_components_manage(cls, ocls);
00836 
00837 #ifdef TRACE
00838   printf("ocls %s [%p] %s in_schema=%s is_removed=%s\n", ocls->getName(), ocls,
00839          ocls->getOid().toString(), odlIsInSchema(db, ocls) ? "yes" : "no",
00840          ocls->isRemoved() ? "yes" : "no");
00841   printf("cls %s [%p] %s in_schema=%s is_removed=%s\n\n", cls->getName(), cls,
00842          cls->getOid().toString(), odlIsInSchema(db, cls) ? "yes" : "no",
00843          cls->isRemoved() ? "yes" : "no");
00844 #endif
00845   clsconv->setOidO(ocls->getOid());
00846   if (!ocls->isRemoved() && ocls->getOid().isValid())
00847     {
00848 #ifdef TRACE
00849       printf("removing class %p %s %s keeping %p\n", ocls, ocls->getName(),
00850              ocls->getOid().toString(), cls);
00851 #endif
00852       odlPostUpdate::add(ocls->getOid(), (Class *)cls);
00853       Status s = const_cast<Class *>(ocls)->remove_r();
00854       if (s) return s;
00855 
00856       s = invalidateCollClassOid(db, ocls);
00857       if (s) return s;
00858       s = invalidateInverseOid(db, ocls);
00859       if (s) return s;
00860       s = reportExtentOid(db, ocls);
00861       if (s) return s;
00862       ObjectPeer::setOid(const_cast<Class *>(cls), Oid::nullOid);
00863       const_cast<Class *>(cls)->setXInfo(IDB_XINFO_CLASS_UPDATE);
00864     }
00865 
00866 #ifdef TRACE
00867   printf("[after] ocls %s [%p] %s in_schema=%s is_removed=%s\n", ocls->getName(), ocls,
00868          ocls->getOid().toString(), odlIsInSchema(db, ocls) ? "yes" : "no",
00869          ocls->isRemoved() ? "yes" : "no");
00870   printf("[after] cls %s [%p] %s in_schema=%s is_removed=%s\n\n", cls->getName(), cls,
00871          cls->getOid().toString(), odlIsInSchema(db, cls) ? "yes" : "no",
00872          cls->isRemoved() ? "yes" : "no");
00873 #endif
00874 
00875   clsconv->setClsname(cls->getName());
00876   clsconv->setAttrname(item->getName());
00877   clsconv->setAttrnum(item->getNum());
00878   return Success;
00879 }
00880 
00881 Status
00882 odlUpdateAttribute::postPerform(Database *db, Schema *m)
00883 {
00884   if (!clsconv)
00885     return Success;
00886 
00887   clsconv->setOidN(cls->getOid());
00888   return clsconv->realize();
00889 }
00890 
00891 Status
00892 odlAddAttribute::prePerform(Database *db, Schema *m)
00893 {
00894   display();
00895   Offset offset;
00896   Size item_psize, psize, item_inisize;
00897   item->getPersistentIDR(offset, item_psize, psize, item_inisize);
00898 
00899   Status s = initClassConv(db);
00900   if (s) return s;
00901 
00902   clsconv->setUpdtype(ADD_ATTR);
00903   clsconv->setOffsetO(0);
00904   clsconv->setOffsetN(offset);
00905   clsconv->setSizeO(0);
00906   clsconv->setSizeN(psize);
00907 
00908 #ifdef TRACE
00909   printf("add attribute %s: %d %d %d %d\n", item->getName(), offset,
00910          item_psize, psize, item_inisize);
00911 #endif
00912   return Success;
00913 }
00914 
00915 Status
00916 odlRemoveAttribute::prePerform(Database *db, Schema *m)
00917 {
00918   display();
00919 
00920   Offset offset;
00921   Size item_psize, psize, item_inisize;
00922   item->getPersistentIDR(offset, item_psize, psize, item_inisize);
00923 
00924   Status s = initClassConv(db);
00925   if (s) return s;
00926 
00927   clsconv->setUpdtype(RMV_ATTR);
00928   clsconv->setOffsetO(0);
00929   clsconv->setOffsetN(offset);
00930   clsconv->setSizeO(0);
00931   clsconv->setSizeN(psize);
00932 
00933 #ifdef TRACE
00934   printf("remove attribute %s: %d %d %d %d\n", item->getName(), offset,
00935          item_psize, psize, item_inisize);
00936 #endif
00937 
00938   return Success;
00939 }
00940 
00941 Status
00942 odlRenameAttribute::prePerform(Database *db, Schema *m)
00943 {
00944   display();
00945   const_cast<Class *>(cls)->touch();
00946   return Success;
00947 }
00948 
00949 #define CNV(CLSTYP, CNVTYP) \
00950  if (ncls->as##CLSTYP##Class()) { \
00951     clsconv->setCnvtype(CNVTYP); \
00952     odlUpdateItem::initDisplay(); \
00953     fprintf(odl_fd, "Converting attribute %s::%s using " #CNVTYP " conversion method\n", cls->getName(), item->getName()); \
00954     return Success; \
00955  }
00956 
00957 #define CNV_TO_CHAR(CNVTYP) \
00958  if (ncls->asCharClass()) { \
00959     odlUpdateItem::initDisplay(); \
00960     if (item->isVarDim()) { \
00961      clsconv->setCnvtype(CNVTYP##_TO_STRING); \
00962      fprintf(odl_fd, "Converting attribute %s::%s using " #CNVTYP "_TO_STRING conversion method\n", cls->getName(), item->getName()); \
00963     } \
00964     else { \
00965      clsconv->setCnvtype(CNVTYP##_TO_CHAR); \
00966      fprintf(odl_fd, "Converting attribute %s::%s using " #CNVTYP "_TO_CHAR conversion method\n", cls->getName(), item->getName()); \
00967     } \
00968     return Success; \
00969  }
00970 
00971 #define CNV_FROM_CHAR(CLSTYP, CNVTYP) \
00972  if (ncls->as##CLSTYP##Class()) { \
00973     odlUpdateItem::initDisplay(); \
00974     if (oitem->isVarDim()) { \
00975       clsconv->setCnvtype(STRING_TO_##CNVTYP); \
00976       fprintf(odl_fd, "Converting attribute %s::%s using STRING_TO_" #CNVTYP " conversion method\n", cls->getName(), item->getName()); \
00977     } \
00978     else { \
00979       clsconv->setCnvtype(CHAR_TO_##CNVTYP); \
00980       fprintf(odl_fd, "Converting attribute %s::%s using CHAR_TO_" #CNVTYP " conversion method\n", cls->getName(), item->getName()); \
00981     } \
00982     return Success; \
00983  }
00984 
00985 #define CNV_FROM_CHAR_TO_CHAR() \
00986  if (ncls->asCharClass()) { \
00987     odlUpdateItem::initDisplay(); \
00988     if (item->isVarDim()) { \
00989       if (oitem->isVarDim()) \
00990        return Exception::make(IDB_ERROR, "internal error: unexpected string to string conversion"); \
00991       clsconv->setCnvtype(CHAR_TO_STRING); \
00992       fprintf(odl_fd, "Converting attribute %s::%s using CHAR_TO_STRING conversion method\n", cls->getName(), item->getName()); \
00993     } \
00994     else { \
00995       if (oitem->isVarDim()) {\
00996         clsconv->setCnvtype(STRING_TO_CHAR); \
00997         fprintf(odl_fd, "Converting attribute %s::%s using STRING_TO_CHAR conversion method\n", cls->getName(), item->getName()); \
00998      } \
00999      else { \
01000         clsconv->setCnvtype(CHAR_TO_CHAR); \
01001         fprintf(odl_fd, "Converting attribute %s::%s using CHAR_TO_CHAR conversion method\n", cls->getName(), item->getName()); \
01002      } \
01003    } \
01004     return Success; \
01005 }
01006 
01007 static Index *
01008 odl_fill_index(Index *ridx, Index *idx)
01009 {
01010   return 0;
01011 }
01012 
01013 static Index *
01014 odl_clone_index(Index *idx)
01015 {
01016   return 0;
01017 }
01018 
01019 Status
01020 odlConvertAttribute::prePerformBasic(Schema *m, const Class *ncls,
01021                                      const Class *ocls)
01022 {
01023   assert(0);
01024 
01025   if (ocls->asInt16Class()) {
01026     CNV(Int16, INT16_TO_INT16);
01027     CNV(Int32, INT16_TO_INT32);
01028     CNV(Int64, INT16_TO_INT64);
01029     CNV(Float, INT16_TO_FLOAT);
01030     CNV(Byte, INT16_TO_BYTE);
01031     CNV_TO_CHAR(INT16);
01032   }
01033   else if (ocls->asInt32Class()) {
01034     CNV(Int32, INT32_TO_INT32);
01035     CNV(Int16, INT32_TO_INT16);
01036     CNV(Int64, INT32_TO_INT64);
01037     CNV(Float, INT32_TO_FLOAT);
01038     CNV(Byte, INT32_TO_BYTE);
01039     CNV_TO_CHAR(INT32);
01040   }
01041   else if (ocls->asInt64Class()) {
01042     CNV(Int64, INT64_TO_INT64);
01043     CNV(Int16, INT64_TO_INT16);
01044     CNV(Int32, INT64_TO_INT32);
01045     CNV(Float, INT64_TO_FLOAT);
01046     CNV(Byte, INT64_TO_BYTE);
01047     CNV_TO_CHAR(INT64);
01048   }
01049   else if (ocls->asFloatClass()) {
01050     CNV(Float, FLOAT_TO_FLOAT);
01051     CNV(Int16, FLOAT_TO_INT16);
01052     CNV(Int32, FLOAT_TO_INT32);
01053     CNV(Int64, FLOAT_TO_INT64);
01054     CNV(Byte, FLOAT_TO_BYTE);
01055     CNV_TO_CHAR(FLOAT);
01056   }
01057   else if (ocls->asCharClass()) {
01058     CNV_FROM_CHAR_TO_CHAR();
01059     CNV_FROM_CHAR(Int16, INT16);
01060     CNV_FROM_CHAR(Int32, INT32);
01061     CNV_FROM_CHAR(Int64, INT64);
01062     CNV_FROM_CHAR(Byte, BYTE);
01063     CNV_FROM_CHAR(Float, FLOAT);
01064   }
01065   else if (ocls->asByteClass()) {
01066     CNV(Byte, BYTE_TO_BYTE);
01067     CNV(Int16, BYTE_TO_INT16);
01068     CNV(Int32, BYTE_TO_INT32);
01069     CNV(Int64, BYTE_TO_INT64);
01070     CNV(Float, BYTE_TO_FLOAT);
01071     CNV_TO_CHAR(BYTE);
01072   }
01073   else if (ocls->asEnumClass()) {
01074     CNV(Enum, ENUM_TO_ENUM);
01075     CNV(Int16, ENUM_TO_INT16);
01076     CNV(Int32, ENUM_TO_INT32);
01077     CNV(Int64, ENUM_TO_INT64);
01078     CNV(Byte, ENUM_TO_BYTE);
01079     CNV(Char, ENUM_TO_CHAR);
01080     CNV(Float, ENUM_TO_FLOAT);
01081   }
01082   else
01083     return Exception::make(IDB_ERROR,
01084                               "conversion from class %s to class %s "
01085                               "is not supported",
01086                               ocls->getName(), ncls->getName());
01087 
01088   return Success;
01089 }
01090 
01091 static inline int
01092 get_dim(const TypeModifier &tmod)
01093 {
01094   return (tmod.mode & TypeModifier::VarDim) ? (-tmod.pdims) : tmod.pdims;
01095 }
01096 
01097 #define NOT_(X, Y) \
01098 if (clsconv->getCnvtype() == X) \
01099    return Exception::make(IDB_ERROR, "conversion " #X " is not " #Y)
01100 
01101 #define NOT_IMPLEMENTED(X) \
01102   NOT_(X, "yet implemented")
01103 
01104 #define NOT_SUPPORTED(X) \
01105   NOT_(X, "supported")
01106 
01107 Status
01108 odlConvertAttribute::prePerform(Database *db, Schema *m)
01109 {
01110   odlUpdateItem::initDisplay();
01111 
01112   const Class *ocls = oitem->getClass();
01113   const TypeModifier &otmod = oitem->getTypeModifier();
01114   const Class *ncls = item->getClass();
01115   const TypeModifier &tmod = item->getTypeModifier();
01116 
01117   if (tmod.ndims > 1 || otmod.ndims > 1)
01118     return Exception::make(IDB_ERROR, "attribute %s::%s: "
01119                               "no automatic conversion for multi-"
01120                               "dimensional arrays",
01121                               cls->getName(), item->getName());
01122 
01123   Status s = initClassConv(db);
01124   if (s) return s;
01125   Offset offset_o, offset_n;
01126   Size dummy, psize_o, psize_n, item_psize_o, item_psize_n;
01127 
01128   item->getPersistentIDR(offset_n, item_psize_n, psize_n, dummy);
01129   oitem->getPersistentIDR(offset_o, item_psize_o, psize_o, dummy);
01130 
01131   clsconv->setOffsetO(offset_o);
01132   clsconv->setOffsetN(offset_n);
01133   clsconv->setUpdtype(CNV_ATTR);
01134 
01135   clsconv->setSrcDim(get_dim(otmod));
01136   clsconv->setDestDim(get_dim(tmod));
01137 
01138 #ifdef TRACE
01139   printf("odlConvertAttribute(%s::%s) dims = %d vs. %d\n",
01140          cls->getName(), item->getName(), clsconv->getSrcDim(),
01141          clsconv->getDestDim());
01142 #endif
01143 
01144   // check numeric conversions
01145   clsconv->setSizeO(psize_o);
01146   clsconv->setSizeN(psize_n);
01147 
01148   if (ncls->asBasicClass() && (ocls->asBasicClass() || ocls->asEnumClass())) 
01149     return prePerformBasic(m, ncls, ocls);
01150 
01151   // check class modification propagation
01152   if (/*tmod.compare(&otmod) &&*/ !strcmp(ncls->getName(), ocls->getName()))
01153     {
01154       if (!oitem->isIndirect() && !item->isIndirect() &&
01155           !ncls->asCollectionClass())
01156         {
01157 #ifdef TRACE
01158           printf("class %s: class modification propagation on attribute "
01159                  "%s::%s\n",
01160                  cls->getOid().toString(), cls->getName(), item->getName());
01161           printf("new class %s %s\n", ncls->getOid().toString(),
01162                  ncls->getName());
01163           printf("old class %s %s\n", ocls->getOid().toString(),
01164                  ocls->getName());
01165           printf("attribute old class oid %s\n",
01166                  oitem->getClass()->getOid().toString());
01167 #endif
01168 
01169 #ifdef VERBOSE_2
01170           odlUpdateItem::initDisplay();
01171           fprintf(odl_fd, "Converting attribute %s::%s", cls->getName(),
01172                   item->getName());
01173           fprintf(odl_fd, " using CLASS_TO_CLASS conversion method\n");
01174 #endif
01175 
01176           // changed the 12/06/01
01177           //clsconv->setRoidO(ncls->getOid());
01178           clsconv->setSizeO(item_psize_o);
01179           clsconv->setSizeN(item_psize_n);
01180           clsconv->setRoidO(ocls->getOid());
01181           clsconv->setCnvtype(CLASS_TO_CLASS);
01182           //clsconv->trace();
01183           return Success;
01184         }
01185 
01186       if (!oitem->isIndirect() && item->isIndirect())
01187         return Exception::make(IDB_ERROR, "attribute %s::%s: "
01188                                   "conversion between a direct "
01189                                   "and an indirect attribute is not supported",
01190                                   cls->getName(), item->getName());
01191 
01192       if (oitem->isIndirect() && !item->isIndirect())
01193         return Exception::make(IDB_ERROR, "attribute %s::%s: "
01194                                   "conversion between an indirect "
01195                                   "and a direct attribute is not supported",
01196                                   cls->getName(), item->getName());
01197 
01198       clsconv->setCnvtype(NIL_CNV);
01199       /*
01200       clsconv->release();
01201       clsconv = 0;
01202       */
01203 #ifdef TRACE
01204       printf("nil conversion on %s::%s\n", cls->getName(), item->getName());
01205 #endif
01206       return Success;
01207     }
01208 
01209   // check user conversions
01210 
01211   // check uptype conversions
01212 
01213   // check no conversions: for instance, because of the renaming of a class
01214 
01215   //NOT_IMPLEMENTED(CHAR_TO_STRING);
01216   NOT_SUPPORTED(STRING_TO_CHAR);
01217   //NOT_IMPLEMENTED(INT16_TO_STRING);
01218   NOT_SUPPORTED(STRING_TO_INT16);
01219   //NOT_IMPLEMENTED(INT32_TO_STRING);
01220   NOT_SUPPORTED(STRING_TO_INT32);
01221   //NOT_IMPLEMENTED(INT64_TO_STRING);
01222   NOT_SUPPORTED(STRING_TO_INT64);
01223   //NOT_IMPLEMENTED(FLOAT_TO_STRING);
01224   NOT_SUPPORTED(STRING_TO_FLOAT);
01225   //NOT_IMPLEMENTED(BYTE_TO_STRING);
01226   NOT_SUPPORTED(STRING_TO_BYTE);
01227 
01228   return Exception::make(IDB_ERROR, "conversion from class %s to class %s "
01229                             "is not supported",
01230                             ocls->getName(), ncls->getName());
01231 }
01232 
01233 Status
01234 odlReorderAttribute::prePerform(Database *db, Schema *m)
01235 {
01236   display();
01237   return Success;
01238 }
01239 
01240 Status
01241 odlMigrateAttribute::prePerform(Database *db, Schema *m)
01242 {
01243   display();
01244   return Success;
01245 }
01246 
01247 void
01248 odlReorderAttribute::display()
01249 {
01250   odlUpdateItem::initDisplay();
01251 
01252   fprintf(odl_fd, "Ignoring %s::%s position in the ODL:",
01253           cls->getName(), item->getName());
01254 
01255   fprintf(odl_fd, " has been reordered from #%d to #%d position\n",
01256           asReorderAttribute()->oldnum, asReorderAttribute()->newnum);
01257 }
01258 
01259 void
01260 odlReorderAttribute::displayDiff(Database *db, const char *odlfile)
01261 {
01262   odlUpdateItem::initDisplayDiff(db, odlfile);
01263 
01264   fprintf(odl_fd, "  class %s: attribute %s", cls->getName(), item->getName());
01265   
01266   fprintf(odl_fd, " automatically reordered from #%d to #%d in the ODL\n",
01267           oldnum, newnum);
01268 }
01269 
01270 void
01271 odlConvertAttribute::display()
01272 {
01273   odlUpdateItem::initDisplay();
01274 
01275   fprintf(odl_fd, "Converting attribute %s::%s", cls->getName(),
01276           item->getName());
01277 
01278   if (upd_hints)
01279     fprintf(odl_fd, " using %s method", upd_hints->detail);
01280 
01281   fprintf(odl_fd, "\n");
01282 }
01283 
01284 void
01285 odlConvertAttribute::displayDiff(Database *db, const char *odlfile)
01286 {
01287   odlUpdateItem::initDisplayDiff(db, odlfile);
01288 
01289   fprintf(odl_fd, "  class %s: attribute %s", cls->getName(), item->getName());
01290   
01291   fprintf(odl_fd, " must be converted");
01292   if (upd_hints)
01293     fprintf(odl_fd, " using %s method", upd_hints->detail);
01294 
01295   fprintf(odl_fd, "\n");
01296 }
01297 
01298 void
01299 odlRenameAttribute::display()
01300 {
01301   odlUpdateItem::initDisplay();
01302 
01303   fprintf(odl_fd, "Renaming attribute %s::%s", cls->getName(),
01304           item->getName());
01305 
01306   if (asRenameAttribute())
01307     fprintf(odl_fd, " from %s", upd_hints->detail);
01308 
01309   if (upd_hints->detail2)
01310     fprintf(odl_fd, " using %s method", upd_hints->detail2);
01311 
01312   fprintf(odl_fd, "\n");
01313 }
01314 
01315 void
01316 odlRenameAttribute::displayDiff(Database *db, const char *odlfile)
01317 {
01318   odlUpdateItem::initDisplayDiff(db, odlfile);
01319 
01320   fprintf(odl_fd, "  class %s: attribute %s", cls->getName(), item->getName());
01321   
01322   fprintf(odl_fd, " must be renamed from %s", upd_hints->detail);
01323 
01324   if (upd_hints->detail2)
01325     fprintf(odl_fd, " using %s method", upd_hints->detail2);
01326 
01327   fprintf(odl_fd, "\n");
01328 }
01329 
01330 void
01331 odlMigrateAttribute::display()
01332 {
01333   odlUpdateItem::initDisplay();
01334 
01335   fprintf(odl_fd, "Migrating attribute %s::%s", cls->getName(),
01336           item->getName());
01337 
01338   fprintf(odl_fd, " to %s::%s", upd_hints->detail, upd_hints->detail2);
01339 
01340   if (upd_hints->detail3)
01341     fprintf(odl_fd, " using %s method", upd_hints->detail3);
01342 
01343   fprintf(odl_fd, "\n");
01344 }
01345 
01346 void
01347 odlMigrateAttribute::displayDiff(Database *db, const char *odlfile)
01348 {
01349   odlUpdateItem::initDisplayDiff(db, odlfile);
01350 
01351   fprintf(odl_fd, "  class %s: attribute %s", cls->getName(), item->getName());
01352   
01353   fprintf(odl_fd, " must migrate to %s::%s", upd_hints->detail, upd_hints->detail2);
01354 
01355   if (upd_hints->detail3)
01356     fprintf(odl_fd, " using %s method", upd_hints->detail3);
01357 
01358   fprintf(odl_fd, "\n");
01359 }
01360 
01361 }

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