00001
00002 #include "rdbModel/Management/XercesBuilder.h"
00003 #include "rdbModel/Management/Manager.h"
00004 #include "rdbModel/Tables/Table.h"
00005 #include "rdbModel/Tables/Column.h"
00006 #include "rdbModel/Tables/Assertion.h"
00007 #include "rdbModel/Tables/Datatype.h"
00008 #include "rdbModel/Tables/Index.h"
00009 #include "rdbModel/Tables/Set.h"
00010 #include "rdbModel/Tables/Query.h"
00011 #include "rdbModel/Tables/InterRow.h"
00012 #include "rdbModel/Tables/Supersede.h"
00013 #include "rdbModel/Tables/InsertNew.h"
00014 #include "facilities/Util.h"
00015 #include "xmlBase/XmlParser.h"
00016 #include "xmlBase/Dom.h"
00017 #include <iostream>
00018 #include <cstdlib>
00019
00020
00021 #define SCHEMA_MAJOR_VERSION 2
00022 #define SCHEMA_MINOR_VERSION 0
00023 namespace rdbModel {
00024 using XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument;
00025 using XERCES_CPP_NAMESPACE_QUALIFIER DOMElement;
00026
00027 XercesBuilder::XercesBuilder() : Builder(), m_doc(0), m_rdb(0) {
00028 }
00029
00030 unsigned int XercesBuilder::parseInput(const std::string& filename) {
00031 xmlBase::XmlParser parser;
00032
00033 parser.doSchema(true);
00034
00035
00036 m_doc = parser.parse(filename.c_str());
00037
00038 return (m_doc == 0) ? 0xffffffff : 0;
00039 }
00040
00041 int XercesBuilder::buildRdb() {
00042 using xmlBase::Dom;
00043
00044 Manager* man = Manager::getManager();
00045
00046 if (m_doc == 0 ) return 0;
00047 m_rdb = man->getRdb();
00048 DOMElement* docElt = m_doc->getDocumentElement();
00049
00050
00051
00052 m_rdb->m_dbName = Dom::getAttribute(docElt, "dbs");
00053 m_rdb->m_majorVersion = 0;
00054 m_rdb->m_minorVersion = 0;
00055
00056 std::string versionString = Dom::getAttribute(docElt, "SchemaVersion");
00057 if (!versionString.size()) {
00058 versionString = Dom::getAttribute(docElt, "DTDversion");
00059 }
00060
00061 unsigned dotPos = versionString.find('.');
00062
00063 std::string minorStr = std::string(versionString, dotPos+1);
00064
00065 versionString.resize(dotPos);
00066
00067 try {
00068 m_rdb->m_majorVersion = facilities::Util::stringToInt(versionString);
00069 m_rdb->m_minorVersion = facilities::Util::stringToInt(minorStr);
00070 }
00071 catch (facilities::WrongType ex) {
00072 std::cerr << "rdbModel::XercesBuilder: Bad version string " << std::endl;
00073 }
00074 m_rdb->m_CVSid = Dom::getAttribute(docElt, "CVSid");
00075 if (m_rdb->m_majorVersion != SCHEMA_MAJOR_VERSION) {
00076 std::cerr << "Schema major version " << m_rdb->m_majorVersion
00077 << " doesn't match expected " << SCHEMA_MAJOR_VERSION
00078 << std::endl;
00079 std::cerr << "Bye for now";
00080 std::cerr.flush();
00081 exit(1);
00082 }
00083
00084
00085 std::vector<DOMElement*> tables;
00086 Dom::getChildrenByTagName(docElt, "table", tables);
00087 unsigned int nTable = tables.size();
00088 unsigned int processed = 0;
00089
00090 for (unsigned int iTable = 0; iTable < nTable; iTable++) {
00091 Table* newTable = buildTable(tables[iTable]);
00092
00093 if (newTable) {
00094 m_rdb->addTable(newTable);
00095 processed++;
00096 }
00097 }
00098 return nTable - processed;
00099 }
00100
00101 Table* XercesBuilder::buildTable(DOMElement* tableElt) {
00102 using xmlBase::Dom;
00103
00104 Table* newTable = new Table;
00105 newTable->m_name = Dom::getAttribute(tableElt, "name");
00106 newTable->m_version = Dom::getAttribute(tableElt, "version");
00107 newTable->m_comment = Dom::getAttribute(tableElt, "comment");
00108
00109 std::vector<DOMElement* > children;
00110 Dom::getChildrenByTagName(tableElt, "col", children);
00111 unsigned int nChild = children.size();
00112
00113
00114 for (unsigned int iCol = 0; iCol < nChild; iCol++) {
00115 Column* newCol = buildColumn(children[iCol], newTable);
00116
00117 if (newCol) {
00118 newTable->addColumn(newCol);
00119 }
00120 }
00121
00122 newTable->sortColumns();
00123
00124
00125 DOMElement* primaryKey =
00126 Dom::findFirstChildByName(tableElt, "primary");
00127 if (primaryKey != 0) {
00128 Index* newIndex = buildIndex(primaryKey, true, newTable);
00129 if (newIndex) {
00130 newIndex->m_myTable = newTable;
00131 newTable->addIndex(newIndex);
00132 }
00133 }
00134 newTable->setPrimaryKeyCol();
00135
00136
00137 Dom::getChildrenByTagName(tableElt, "index", children);
00138 nChild = children.size();
00139
00140 for (unsigned int iIndex = 0; iIndex < nChild; iIndex++) {
00141 Index* newIndex = buildIndex(children[iIndex], false, newTable);
00142 if (newIndex) {
00143 newTable->addIndex(newIndex);
00144 }
00145 }
00146
00147
00148
00149
00150 Dom::getChildrenByTagName(tableElt, "assert", children);
00151 nChild = children.size();
00152
00153 for (unsigned int iAssert = 0; iAssert < nChild; iAssert++) {
00154 Assertion* newAssert = buildAssertion(children[iAssert], newTable);
00155 if (newAssert) {
00156 newTable->addAssert(newAssert);
00157 }
00158 }
00159
00160 Assertion* v = newTable->getAssertionByName("validRow");
00161 newTable->setValidRow(v);
00162
00163 DOMElement* iNewElt = Dom::findFirstChildByName(tableElt, "insertNew");
00164 if (iNewElt) {
00165 newTable->m_iNew = buildInsertNew(iNewElt, newTable);
00166 }
00167 DOMElement* supElt = Dom::findFirstChildByName(tableElt, "supersede");
00168 if (supElt) {
00169 newTable->m_sup = buildSupersede(supElt, newTable);
00170 }
00171
00172 return newTable;
00173 }
00174
00175 Column* XercesBuilder::buildColumn(DOMElement* e, Table* myTable) {
00176 using xmlBase::Dom;
00177
00178 Column* newCol = new Column(myTable);
00179
00180 newCol->m_name = Dom::getAttribute(e, "name");
00181 DOMElement* com = Dom::findFirstChildByName(e, "comment");
00182 newCol->m_comment = Dom::getTextContent(com);
00183
00184 DOMElement* src = Dom::findFirstChildByName(e, "src");
00185
00186 newCol->m_null = (Dom::getAttribute(src, "null") == "true");
00187 newCol->m_stickyInsert =
00188 (Dom::getAttribute(src, "stickyInsert") == "true");
00189
00190 DOMElement* child = Dom::getFirstChildElement(src);
00191 if (Dom::checkTagName(child, "default")) {
00192 newCol->m_from = Column::FROMdefault;
00193 newCol->m_default = Dom::getAttribute(child, "value");
00194 }
00195 else if (Dom::checkTagName(child, "from")) {
00196 std::string agent = Dom::getAttribute(child, "agent");
00197 if (agent == "auto_increment") {
00198 newCol->m_from = Column::FROMautoIncrement;
00199 }
00200 else if (agent == "now") {
00201 newCol->m_from = Column::FROMnow;
00202 }
00203 else if (agent == "enduser") {
00204 newCol->m_from = Column::FROMendUser;
00205 }
00206 else if (agent == "service") {
00207 newCol->m_from = Column::FROMprogram;
00208 std::string contents = Dom::getAttribute(child, "contents");
00209 if (contents == "service_name") {
00210 newCol->m_contents = Column::CONTENTSserviceName;
00211 }
00212 else if (contents == "username") {
00213 newCol->m_contents = Column::CONTENTSusername;
00214 }
00215 else if (contents == "insert_time") {
00216 newCol->m_contents = Column::CONTENTSinsertTime;
00217 }
00218 else if (contents == "update_time") {
00219 newCol->m_contents = Column::CONTENTSupdateTime;
00220 }
00221
00222 }
00223
00224 }
00225
00226 DOMElement* dtype = Dom::findFirstChildByName(e, "type");
00227 newCol->m_type = buildDatatype(dtype);
00228
00229 return newCol;
00230 }
00231
00232 Datatype* XercesBuilder::buildDatatype(DOMElement* e) {
00233 using xmlBase::Dom;
00234
00235 Datatype* newType = new Datatype;
00236 newType->setType(Dom::getAttribute(e, "typename"));
00237
00238 if (Dom::hasAttribute(e, "size")) {
00239 try {
00240 newType->m_outputSize = Dom::getIntAttribute(e, "size");
00241 }
00242 catch (xmlBase::DomException ex) {
00243 std::cerr << "Error in rdb database description file" << std::endl;
00244 std::cerr << ex.getMsg() << std::endl;
00245 std::cerr << "Ignoring column size specification " << std::endl;
00246 newType->m_outputSize = -1;
00247 }
00248 }
00249 else newType->m_outputSize = -1;
00250 if ((newType->m_outputSize == -1) &&
00251 (newType->getType() == Datatype::TYPEchar) ) newType->m_outputSize = 1;
00252 if ((newType->m_outputSize == -1) &&
00253 (newType->getType() == Datatype::TYPEvarchar) ) {
00254 std::cerr << "Error in rdb database description file: " << std::endl;
00255 std::cerr << "Missing size spec. for varchar field " << std::endl;
00256 delete newType;
00257 newType = 0;
00258 return newType;
00259 }
00260
00261
00262 DOMElement* restrict = Dom::getFirstChildElement(e);
00263
00264 if (restrict != 0) {
00265 DOMElement* rtype = Dom::getFirstChildElement(restrict);
00266 std::string tagname = Dom::getTagName(rtype);
00267 if ((newType->m_type == Datatype::TYPEenum) &&
00268 (tagname != std::string("enum") ) ) {
00269 std::cerr << "From rdbMode::XercesBuilder::buildDatatype" << std::endl;
00270 std::cerr << "Bad enum type. Missing value list " << std::endl;
00271 delete newType;
00272 newType = 0;
00273 return newType;
00274 }
00275
00276 if (tagname == std::string("nonnegative")) {
00277 newType->m_restrict = Datatype::RESTRICTnonneg;
00278 if (newType->m_isInt) newType->m_minInt = 0;
00279 }
00280 else if (tagname == std::string("positive")) {
00281 newType->m_restrict = Datatype::RESTRICTpos;
00282 if (newType->m_isInt) newType->m_minInt = 1;
00283 }
00284 else if (tagname == std::string("interval")) {
00285 newType->setInterval(Dom::getAttribute(rtype, "min"),
00286 Dom::getAttribute(rtype, "max"));
00287 }
00288 else if (tagname == std::string("file")) {
00289 newType->m_restrict = Datatype::RESTRICTfile;
00290 }
00291 else if (tagname == std::string("enum")) {
00292 newType->m_restrict = Datatype::RESTRICTenum;
00293 Enum* newEnum = new Enum();
00294 newEnum->m_required =
00295 (Dom::getAttribute(rtype, "use") == "require");
00296 if (!(newEnum->m_required) &&
00297 (newType->m_type == Datatype::TYPEenum)) {
00298 delete newEnum;
00299 delete newType;
00300 std::cerr << "From rdbMode::XercesBuilder::buildDatatype"
00301 << std::endl;
00302 std::cerr << "Bad enum type. List must be 'required' " << std::endl;
00303 newType = 0;
00304 return newType;
00305 }
00306
00307 std::string enums = Dom::getAttribute(rtype, "values");
00308
00309 unsigned int start = 0;
00310 std::string::size_type blankLoc = enums.find(std::string(" "), start);
00311
00312 while (blankLoc != std::string::npos) {
00313 newEnum->m_choices.push_back(enums.substr(start, blankLoc-start));
00314 start = blankLoc + 1;
00315 blankLoc = enums.find(std::string(" "), start);
00316 }
00317 newEnum->m_choices.push_back(enums.substr(start));
00318 newType->m_enum = newEnum;
00319 }
00320 }
00321 else {
00322 newType->m_restrict = Datatype::RESTRICTnone;
00323 if (newType->m_type == Datatype::TYPEenum) {
00324 std::cerr << "From rdbMode::XercesBuilder::buildDatatype"
00325 << std::endl;
00326 std::cerr << "Bad enum type. Missing value list " << std::endl;
00327 delete newType;
00328 newType = 0;
00329 }
00330 }
00331 return newType;
00332 }
00333
00334 Index* XercesBuilder::buildIndex(DOMElement* e, bool primaryElt,
00335 Table* myTable) {
00336 using xmlBase::Dom;
00337
00338 Index* newIndex = new Index(myTable);
00339
00340 if (primaryElt) {
00341 newIndex->m_primary = true;
00342 std::string col = newIndex->m_name = Dom::getAttribute(e, "col");
00343 newIndex->m_indexCols.push_back(newIndex->m_name);
00344 Column* myCol = myTable->getColumnByName(col);
00345 myCol->m_isPrimaryKey = true;
00346 }
00347 else {
00348 newIndex->m_name = Dom::getAttribute(e, "name");
00349
00350 std::string primaryVal =
00351 Dom::getAttribute(e, "primary");
00352 newIndex->m_primary = (primaryVal == "yes");
00353
00354
00355 std::string cols = Dom::getAttribute(e, "cols");
00356
00357
00358 if (newIndex->m_primary) {
00359 Column* myCol = myTable->getColumnByName(cols);
00360 myCol->m_isPrimaryKey = true;
00361 }
00362
00363 unsigned int start = 0;
00364 std::string::size_type blankLoc = cols.find(std::string(" "), start);
00365
00366 while (blankLoc != std::string::npos) {
00367 newIndex->m_indexCols.push_back(cols.substr(start, blankLoc-start));
00368 start = blankLoc + 1;
00369 blankLoc = cols.find(std::string(" "), start);
00370 }
00371 newIndex->m_indexCols.push_back(cols.substr(start));
00372
00373 }
00374 return newIndex;
00375 }
00376
00377 Assertion* XercesBuilder::buildAssertion(DOMElement* e, Table* myTable) {
00378
00379
00380
00381
00382
00383
00384 std::string name = xmlBase::Dom::getAttribute(e, "name");
00385 DOMElement* opElt = xmlBase::Dom::getFirstChildElement(e);
00386 Assertion::Operator* op = buildOperator(opElt, myTable);
00387
00388 Assertion* newAssert = new Assertion(op, myTable);
00389
00390 newAssert->setName(name);
00391 return newAssert;
00392 }
00393
00394
00395 Assertion::Operator* XercesBuilder::buildOperator(DOMElement* e,
00396 Table* myTable) {
00397 using xmlBase::Dom;
00398
00399 std::string opName = Dom::getTagName(e);
00400 OPTYPE opType = OPTYPEisNull;
00401 if ((opName == "isNull") || (opName == "isEmpty")) {
00402 if (opName == "isEmpty") opType = OPTYPEisEmpty;
00403 DOMElement* child = Dom::getFirstChildElement(e);
00404 FIELDTYPE valType;
00405 std::string which = Dom::getAttribute(child, "which");
00406 valType = (which == std::string("old")) ? FIELDTYPEold
00407 : FIELDTYPEtoBe;
00408
00409 return new Assertion::Operator(opType,
00410 Dom::getAttribute(child, "col"),
00411 std::string(""),
00412 valType, valType);
00413
00414
00415 }
00416 else if (opName == "compare") {
00417 std::string relation = Dom::getAttribute(e, "relation");
00418 if (relation == "lessThan") opType = OPTYPElessThan;
00419 else if (relation == "greaterThan") {
00420 opType = OPTYPEgreaterThan;
00421 }
00422 else if (relation == "equal") opType = OPTYPEequal;
00423 else if (relation == "notEqual")
00424 opType = OPTYPEnotEqual;
00425 else if (relation == "lessOrEqual") {
00426 opType = OPTYPElessOrEqual;
00427 }
00428 else if (relation == "greaterOrEqual") {
00429 opType = OPTYPEgreaterOrEqual;
00430 }
00431 DOMElement* child[2];
00432 child[0] = Dom::getFirstChildElement(e);
00433 child[1] = Dom::getSiblingElement(child[0]);
00434
00435 std::string compareArgs[2];
00436
00437 FIELDTYPE valueType[2];
00438 for (unsigned iChild = 0; iChild < 2; iChild++) {
00439
00440
00441
00442
00443
00444
00445 if (Dom::checkTagName(child[iChild], "value")) {
00446 valueType[iChild] = FIELDTYPElit;
00447 compareArgs[iChild] =
00448 Dom::getTextContent(child[iChild]);
00449 }
00450 else {
00451 compareArgs[iChild] =
00452 Dom::getAttribute(child[iChild], "col");
00453
00454 std::string which = Dom::getAttribute(child[iChild],
00455 "which");
00456 if (which == std::string("old")) {
00457 valueType[iChild] = FIELDTYPEold;
00458 } else if (which == std::string("toBe")) {
00459 valueType[iChild] = FIELDTYPEtoBe;
00460 }
00461 else valueType[iChild] = FIELDTYPEask;
00462 }
00463 }
00464 Assertion::Operator* newOp =
00465 new Assertion::Operator(opType, compareArgs[0], compareArgs[1],
00466 valueType[0], valueType[1]);
00467 if (!newOp->validCompareOp(myTable)) {
00468 delete newOp;
00469 return 0;
00470 }
00471 return newOp;
00472 }
00473
00474
00475 else if (opName == "exists") {
00476 std::string tableName;
00477 opType = OPTYPEexists;
00478 if (Dom::hasAttribute(e, "tableName") ) {
00479 tableName =
00480 Dom::getAttribute(e, "tableName");
00481 }
00482 else tableName = myTable->getName();
00483 DOMElement* child = Dom::getFirstChildElement(e);
00484 Assertion::Operator* childOp = buildOperator(child, myTable);
00485 return new Assertion::Operator(opType, tableName, childOp);
00486 }
00487
00488 else if (opName == "or") opType = OPTYPEor;
00489 else if (opName == "and") opType = OPTYPEand;
00490 else if (opName == "not") opType = OPTYPEnot;
00491
00492
00493 std::vector<DOMElement*> children;
00494 std::vector<Assertion::Operator*> childOps;
00495 Dom::getChildrenByTagName(e, "*", children);
00496 unsigned nChild = children.size();
00497 for (unsigned iChild = 0; iChild < nChild; iChild++) {
00498 Assertion::Operator* childOp = buildOperator(children[iChild], myTable);
00499 if (childOp) {
00500 childOps.push_back(childOp);
00501 }
00502 else {
00503 return 0;
00504 }
00505 }
00506 return new Assertion::Operator(opType, childOps);
00507 }
00508
00509 Set* XercesBuilder::buildSet(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* e,
00510 Table* t) {
00511 using xmlBase::Dom;
00512
00513 std::string destCol = Dom::getAttribute(e, "destCol");
00514
00515 std::string destRow = Dom::getAttribute(e, "destRow");
00516 FIELDTYPE destType = (destRow == std::string("old") ) ? FIELDTYPEold :
00517 FIELDTYPEtoBe;
00518
00519
00520 FIELDTYPE srcType;
00521 std::string srcValue;
00522 std::string interp("");
00523 DOMElement* srcElt = Dom::findFirstChildByName(e, "*");
00524 std::string tag = Dom::getTagName(srcElt);
00525 if (tag == std::string("ask")) {
00526 srcType = FIELDTYPEask;
00527 srcValue = "";
00528 }
00529 else if (tag == std::string("value") ) {
00530 srcType = FIELDTYPElit;
00531 srcValue = Dom::getTextContent(srcElt);
00532 interp = Dom::getAttribute(srcElt, "interp");
00533 }
00534 else {
00535 std::string forceStr= Dom::getAttribute(srcElt, "force");
00536 bool force = (forceStr == std::string("true"));
00537 srcValue = Dom::getAttribute(srcElt, "col");
00538 std::string which = Dom::getAttribute(srcElt, "which");
00539 srcType = (which == std::string("old")) ? FIELDTYPEold
00540 : FIELDTYPEtoBe;
00541 if (!force) {
00542 if (srcType == FIELDTYPEold) srcType = FIELDTYPEoldDef;
00543 else srcType = FIELDTYPEtoBeDef;
00544 }
00545 }
00546 return new Set(t, destCol, destType, srcValue, srcType, interp);
00547 }
00548
00549
00550 Supersede*
00551 XercesBuilder::buildSupersede(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* e,
00552 Table* t) {
00553 using xmlBase::Dom;
00554
00555
00556
00557
00558
00559 std::string onlyIfStr = Dom::getAttribute(e, "onlyIf");
00560 Assertion* onlyIf = t->getAssertionByName(onlyIfStr);
00561 Supersede* super = new Supersede(t, onlyIf);
00562
00563
00564
00565 e = Dom::findFirstChildByName(e, "*");
00566 while (e != 0) {
00567 Set* s = buildSet(e, t);
00568 super->addSet(s);
00569 e = Dom::getSiblingElement(e);
00570 }
00571 super->normalize();
00572 return super;
00573 }
00574
00575 Query*
00576 XercesBuilder::buildQuery(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* e,
00577 Table* t) {
00578 using xmlBase::Dom;
00579 std::string whereStr = Dom::getAttribute(e, "assertRef");
00580 Assertion* where = t->getAssertionByName(whereStr);
00581
00582 Query* q = new Query(t, 0, where);
00583 e = Dom::findFirstChildByName(e, "*");
00584 while (e != 0) {
00585 q->addSelect(Dom::getTextContent(e));
00586 e = Dom::getSiblingElement(e);
00587 }
00588 return q;
00589 }
00590
00591 InsertNew*
00592 XercesBuilder::buildInsertNew(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* e,
00593 Table* t) {
00594 using xmlBase::Dom;
00595
00596 std::string internalStr = Dom::getAttribute(e, "internalCond");
00597 Assertion* internal = t->getAssertionByName(internalStr);
00598
00599 std::string officialStr = Dom::getAttribute(e, "official");
00600 Assertion* official = t->getAssertionByName(officialStr);
00601
00602 InsertNew* in = new InsertNew(t, internal, official);
00603 e = Dom::findFirstChildByName(e, "*");
00604 while (e != 0) {
00605 InterRow* ir = buildInterRow(e, t);
00606
00607 in->addInterRow(ir);
00608 e = Dom::getSiblingElement(e);
00609 }
00610 return in;
00611 }
00612
00613 InterRow*
00614 XercesBuilder::buildInterRow(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* e,
00615 Table* t) {
00616 using xmlBase::Dom;
00617
00618
00619 XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* queryElt =
00620 Dom::findFirstChildByName(e, "*");
00621 Query* q = buildQuery(queryElt, t);
00622
00623 XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* sib =
00624 Dom::getSiblingElement(queryElt);
00625 bool quit = Dom::checkTagName(sib, "quit");
00626
00627 InterRow* inter = new InterRow(t, q, quit);
00628 if (quit) return inter;
00629
00630
00631 while (sib != 0) {
00632 Set* s = buildSet(sib, t);
00633 inter->addSet(*s);
00634 sib = Dom::getSiblingElement(sib);
00635
00636 }
00637 return inter;
00638 }
00639 }