BadgerDB
|
00001 // 00002 // Author: Jignesh M. Patel 00003 // EECS Department, University of Michigan 00004 // Date: August-October 2001 00005 // 00006 // 00007 00008 00015 #include <stdio.h> 00016 #include <assert.h> 00017 00018 #include <sstream> 00019 #include <cstdlib> 00020 #include <string> 00021 00022 #include "SqlParser.h" 00023 #include "SqlInterp.h" 00024 #include "catalog.h" 00025 #include "query.h" 00026 #include "updates.h" 00027 #include "utility.h" 00028 #include "exceptions/relation_not_found_exception.h" 00029 00030 #define E_OK 0 00031 #define E_INCOMPATIBLE -1 00032 #define E_TOOMANYATTRS -2 00033 #define E_NOLENGTH -3 00034 #define E_INVINTSIZE -4 00035 #define E_INVFLOATSIZE -5 00036 #define E_INVFORMATSTRING -6 00037 #define E_INVSTRLEN -7 00038 #define E_DUPLICATEATTR -8 00039 #define E_TOOLONG -9 00040 #define E_STRINGTOOLONG -10 00041 #define E_CORRUPTSQL -11 00042 #define E_LITERALTYPE -12 00043 00044 00045 #define ERRFP stderr // error message go here 00046 #define MAXATTRS 40 // max. number of attrs in a relation 00047 00048 00049 00050 // 00051 // prefab arrays of useful types 00052 // 00053 00054 static REL_ATTR qual_attrs[MAXATTRS + 1]; 00055 static ATTR_DESCR attr_descrs[MAXATTRS + 1]; 00056 static ATTR_VAL ins_attrs[MAXATTRS + 1]; 00057 static char *names[MAXATTRS + 1]; 00058 00059 static int mk_attrnames(PxxList *list, char *attrnames[], char *relname); 00060 static int mk_qual_attrs(PxxList *list, REL_ATTR qual_attrs[], 00061 char *relname1, char *relname2); 00062 static int mk_attr_descrs(PxxList *list, ATTR_DESCR attr_descrs[]); 00063 static int mk_ins_attrs(PxxPnode *list, ATTR_VAL ins_attrs[]); 00064 static void print_error(const char *errmsg, int errval); 00065 /* 00066 static int parse_format_string(char *format_string, int *type, int *len); 00067 static void *value_of(PxxPnode *n); 00068 static int type_of(PxxPnode *n); 00069 static int length_of(PxxPnode *n); 00070 static void echo_query(PxxPnode *n); 00071 static void print_qual(PxxPnode *n); 00072 static void print_attrnames(PxxPnode *n); 00073 static void print_attrdescrs(PxxPnode *n); 00074 static void print_attrvals(PxxPnode *n); 00075 static void print_primattr(PxxPnode *n); 00076 static void print_qualattr(PxxPnode *n); 00077 static void print_op(int op); 00078 static void print_val(NODE *n); 00079 */ 00080 00081 static int nattrs; 00082 static string resultName; 00083 00084 static attrInfo attrList[MAXATTRS]; 00085 static attrInfo attr1; 00086 static attrInfo attr2; 00087 00088 00089 extern "C" int isatty(int fd); // returns 1 if fd is a tty device 00090 00091 // 00092 // Evaluate the parse tree 00093 // 00094 00095 void PxxInterp::eval(PxxPnode *ptree) 00096 { 00097 // cout << *ptree << endl; 00098 00099 switch(ptree->MyType()) 00100 { 00101 case PxxPnode::Create: 00102 createTable(ptree); 00103 break; 00104 case PxxPnode::Insert: 00105 insertIntoTable(ptree); 00106 break; 00107 case PxxPnode::Drop: 00108 deleteTable((PxxDrop*)ptree); 00109 break; 00110 case PxxPnode::Query: 00111 processQuery(ptree); 00112 break; 00113 case PxxPnode::CreateIndex: 00114 createIndex((PxxCreateIndex*)ptree); 00115 break; 00116 case PxxPnode::DropIndex: 00117 deleteIndex((PxxDropIndex*)ptree); 00118 break; 00119 case PxxPnode::Delete: 00120 deleteTable((PxxDrop*)ptree); 00121 break; 00122 default: 00123 assert(!"Invalid node type"); 00124 } 00125 } 00126 00127 // 00128 // quit the system 00129 // 00130 void PxxInterp::quit(void) 00131 { 00132 Utilities::Quit(); 00133 exit(1); 00134 } 00135 00140 void PxxInterp::createTable(PxxPnode *ptree) 00141 { 00142 // make a list of ATTR_DESCRS suitable for sending to Create 00143 nattrs = mk_attr_descrs(((PxxCreate*)ptree)->AttrList(), attr_descrs); 00144 if (nattrs < 0) 00145 { 00146 print_error("Corrupt attribute list", E_CORRUPTSQL); 00147 return; 00148 } 00149 00150 for(int acnt = 0; acnt < nattrs; acnt++) { 00151 strcpy(attrList[acnt].relName, ((PxxCreate*)ptree) -> RelName()); 00152 strcpy(attrList[acnt].attrName, attr_descrs[acnt].attrName); 00153 attrList[acnt].attrType = attr_descrs[acnt].attrType; 00154 attrList[acnt].attrLen = attr_descrs[acnt].attrLen; 00155 attrList[acnt].attrValue = NULL; 00156 } 00157 00158 // make the call to Create 00159 relCat->createRel(((PxxCreate*)ptree)->RelName(), nattrs, attrList); 00160 00161 return; 00162 } 00163 00167 void PxxInterp::deleteTable(PxxDrop *ptree) 00168 { 00169 // Make a call to Drop. 00170 relCat->destroyRel(ptree->RelName()); 00171 } 00172 00176 void PxxInterp::createIndex(PxxCreateIndex *ptree) 00177 { 00178 // Call the catalog create index 00179 relCat->addIndex(ptree->RelName(), ptree->AttrName()); 00180 } 00181 00185 void PxxInterp::deleteIndex(PxxDropIndex *ptree) 00186 { 00187 relCat->dropIndex(ptree->RelName(), ptree->AttrName()); 00188 } 00189 00194 void PxxInterp::insertIntoTable(PxxPnode *ptree) 00195 { 00196 if(((PxxInsert*)ptree)->ValList() != NULL) 00197 { 00198 // make attribute and value list to be passed to Updates::Insert 00199 nattrs = mk_ins_attrs(ptree, ins_attrs); 00200 if (nattrs < 0) 00201 { 00202 print_error("Invalid attribute list", E_CORRUPTSQL); 00203 return; 00204 } 00205 00206 PxxInsert* pinsert = (PxxInsert*)ptree; 00207 00208 // make the call to Updates::Insert 00209 int acnt; 00210 for(acnt = 0; acnt < nattrs; acnt++) 00211 { 00212 strcpy(attrList[acnt].relName, pinsert->RelName()); 00213 00214 strcpy(attrList[acnt].attrName, ins_attrs[acnt].attrName); 00215 attrList[acnt].attrType = (Datatype)ins_attrs[acnt].valType; 00216 attrList[acnt].attrLen = -1; 00217 attrList[acnt].attrValue = ins_attrs[acnt].value; 00218 } 00219 00220 Updates::Insert(pinsert->RelName(),nattrs,attrList); 00221 00222 // for (acnt = 0; acnt < nattrs; acnt++) 00223 // delete [] (char*)attrList[acnt].attrValue; // Winter 00 00224 00225 return; 00226 } 00227 else 00228 { 00229 /* Doing a load from a file */ 00230 Utilities::Load(((PxxInsert*)ptree)->RelName(), ((PxxInsert*)ptree)->FileName()); 00231 } 00232 } 00233 00239 void PxxInterp::processQuery(PxxPnode *ptree) 00240 { 00241 PxxQuery* pquery = (PxxQuery*)ptree; 00242 PxxList* projnames = pquery->Projs(); 00243 PxxList starList; 00244 PxxList* fromnames = pquery->Froms(); 00245 // PxxList* fromlist = fromnames; 00246 PxxPredTree* predicates = pquery->Preds(); 00247 PxxPredicate* singlepred = 0; 00248 PxxLiteral* literal = 0; 00249 //unsigned int usingtemp = 0; //This is a flag to let us know when we are reading into a temp 00250 int numberoftables; 00251 int attrCnt; 00252 00253 // First, check to see how many tables we are reading from. 00254 // If it is more than one, then the query is a join query 00255 // Check if the table definition exists in the catalog. 00256 ListNode* table = fromnames->Init(); 00257 for(numberoftables = 0; table != NULL; table = table->Next()) 00258 { 00259 PxxRelName* relname = (PxxRelName*)(table->Data()); 00260 RelDesc relDesc; 00261 00262 relCat->getInfo(relname->RelName(), relDesc); 00263 00264 // Add attrnames to the starlist. 00265 AttrDesc* attrDescs; 00266 int numAttrs; 00267 00268 attrCat->getRelInfo(relname->RelName(), numAttrs, attrDescs); 00269 00270 // Add all the attributes of this relations to the starList. 00271 for (int j=0; j<numAttrs; j++) 00272 { 00273 PxxAttrName *aname = new PxxAttrName(attrDescs[j].attrName, 00274 attrDescs[j].relName, 00275 true); 00276 starList.Add(aname); 00277 } 00278 00279 delete [] attrDescs; 00280 00281 numberoftables++; 00282 } 00283 00284 // process * ops in the projection list 00285 if (projnames->Cardinality() == 1 && 00286 ((PxxAttrName*)(projnames->First()->Data()))->Star()) 00287 { 00288 projnames = &starList; 00289 } 00290 00291 // Check to see if an "INTO" was specified, else just write into a default 00292 PxxRelName insert_relname = pquery->RelName(); 00293 00294 RelDesc relDesc; 00295 if(insert_relname.RelName() == NULL) 00296 { 00297 // If we are using a temp relation then the number of 00298 // attributes will just be the number of projected ones 00299 //usingtemp = 1; 00300 resultName = "TMP_BDB"; 00301 unsigned i; 00302 attrCnt = projnames->Cardinality(); 00303 00304 try 00305 { 00306 relCat->getInfo(resultName, relDesc); 00307 std::cerr << "TMP_RES_EXISTS : Database corrupted!" << std::endl; 00308 return; 00309 } 00310 catch(RelationNotFoundException &e) 00311 { 00312 } 00313 00314 // Create the temp result relation 00315 attrInfo *createAttrInfo = new attrInfo[attrCnt]; 00316 00317 ListNode *projdata = projnames->Init(); 00318 PxxAttrName* projattr; 00319 00320 // for each element of the list... 00321 for(i = 0; projdata != NULL && i < MAXATTRS; ++i, projdata = projdata->Next()) 00322 { 00323 projattr = (PxxAttrName*)(projdata->Data()); 00324 00325 // Step through each projection attribute. 00326 AttrDesc attrDesc; 00327 attrCat->getInfo(projattr->RelName(), projattr->AttrName(), attrDesc); 00328 00329 strcpy(createAttrInfo[i].relName, resultName.c_str()); 00330 00331 // Create a unique attribute name 00332 ostringstream newAttrName; 00333 newAttrName << projattr->AttrName() << '.' << i << endl; 00334 strcpy(createAttrInfo[i].attrName, newAttrName.str().c_str()); 00335 00336 createAttrInfo[i].attrType = attrDesc.attrType; 00337 createAttrInfo[i].attrLen = attrDesc.attrLen; 00338 } 00339 00340 if (i != projnames->Cardinality()) 00341 { 00342 print_error("Corrupt SELECT clause", E_CORRUPTSQL); 00343 return; 00344 } 00345 00346 // Create the temp relation. 00347 relCat->createRel(resultName, attrCnt, createAttrInfo); 00348 delete [] createAttrInfo; 00349 } 00350 else 00351 { 00352 resultName = insert_relname.RelName(); 00353 relCat->getInfo(resultName, relDesc); 00354 // if (status != OK && status != RELNOTFOUND) 00355 00356 AttrDesc* resAttrDesc; 00357 attrCat->getRelInfo(resultName, attrCnt, resAttrDesc); 00358 00359 if (attrCnt != relDesc.attrCnt) 00360 { 00361 print_error("Incompatible projection list", E_CORRUPTSQL); 00362 return; 00363 } 00364 00365 // Type check the projection list and the target relation schema 00366 ListNode *temp = projnames->Init(); 00367 PxxAttrName *attr; 00368 00369 int iter; 00370 AttrDesc attrDesc; 00371 // for each qualified attribute in the list... 00372 for(iter = 0; temp != NULL; iter++, temp = temp->Next()) 00373 { 00374 attr = (PxxAttrName*)(temp->Data()); 00375 char* aName = attr->AttrName(); 00376 char* rName = attr->RelName(); 00377 00378 attrCat->getInfo(rName, aName, attrDesc); 00379 00380 if (resAttrDesc[iter].attrType != attrDesc.attrType || resAttrDesc[iter].attrLen != attrDesc.attrLen) 00381 { 00382 print_error("Corrupt projection list", E_CORRUPTSQL); 00383 delete [] resAttrDesc; 00384 return; 00385 } 00386 } 00387 00388 if (iter != relDesc.attrCnt) 00389 { 00390 print_error("Incompatible projection list", E_CORRUPTSQL); 00391 delete [] resAttrDesc; 00392 return; 00393 } 00394 00395 delete [] resAttrDesc; 00396 } 00397 00398 // See if we are doing a join or calling select 00399 if(numberoftables == 1) 00400 { 00401 // Now take care of the projected names and 00402 // make a list of attribute names suitable for passing to select 00403 char *rName = 0; 00404 nattrs = mk_attrnames(projnames, names, rName); 00405 if (nattrs < 0) 00406 { 00407 print_error("Select Clause", E_CORRUPTSQL); 00408 return; 00409 } 00410 00411 for(int acnt = 0; acnt < nattrs; acnt++) 00412 { 00413 strcpy(attrList[acnt].relName, names[nattrs]); 00414 strcpy(attrList[acnt].attrName, names[acnt]); 00415 attrList[acnt].attrType = -1; 00416 attrList[acnt].attrLen = -1; 00417 attrList[acnt].attrValue = NULL; 00418 } 00419 00420 if(predicates != NULL) 00421 { 00422 // cout << "Predicate Node Type: " << predicates->MyType() << endl; 00423 if (predicates->MyType() == PxxPnode::Predicate) 00424 { 00425 singlepred = (PxxPredicate*) predicates; 00426 // cout << *singlepred << endl; 00427 // At this point single pred is the predicate to evaluate. Assume 00428 // that a query never has more than one predicate ... 00429 00430 strcpy(attr1.relName, (*singlepred)[0].AttrName()->RelName()); 00431 strcpy(attr1.attrName, (*singlepred)[0].AttrName()->AttrName()); 00432 attr1.attrLen = -1; 00433 literal = ((*singlepred)[1]).Lit(); 00434 attr1.attrType = literal->Type(); 00435 switch(attr1.attrType) 00436 { 00437 case PxxAttrType::STRING: 00438 attr1.attrValue = (void*)(literal->Char()); 00439 break; 00440 case PxxAttrType::INTEGER: 00441 attr1.attrValue = (void*)(literal->Int()); 00442 break; 00443 case PxxAttrType::DOUBLE: 00444 attr1.attrValue = (void*)(literal->Double()); 00445 break; 00446 } 00447 } 00448 else 00449 { 00450 assert (!"multiple predicates not supported"); 00451 } 00452 00453 } 00454 00455 // make different calls to Operators::Select depending upon whether 00456 // there is a predicate or not 00457 if(predicates == NULL) 00458 { 00459 Operators::Select(resultName, nattrs, attrList, NULL, NOTSET, NULL); 00460 } 00461 else 00462 { 00463 void* filter = 0; 00464 switch(attr1.attrType) 00465 { 00466 case PxxAttrType::STRING: 00467 filter = literal->Char(); 00468 break; 00469 case PxxAttrType::INTEGER: 00470 filter = literal->Int(); 00471 break; 00472 case PxxAttrType::DOUBLE: 00473 filter = literal->Double(); 00474 break; 00475 } 00476 // cerr << "Calling select with a predicate" << endl; 00477 Operator selectop = singlepred->Oper(); 00478 Operators::Select(resultName, nattrs, 00479 attrList, &attr1, 00480 selectop, 00481 filter); 00482 } 00483 } 00484 00485 // JOIN Query: If we are joining then don't actually select, just call join 00486 else 00487 { 00488 PxxPredicate* singlepred = (PxxPredicate*) predicates; 00489 PxxAttrName* first_attr = (*singlepred)[0].AttrName(); 00490 PxxAttrName* second_attr = (*singlepred)[1].AttrName(); 00491 00492 // make an attribute list suitable for passing to join 00493 nattrs = mk_qual_attrs(projnames, 00494 qual_attrs, 00495 first_attr->RelName(), 00496 second_attr->RelName()); 00497 if (nattrs < 0) 00498 { 00499 print_error("Invalid attribute list", E_CORRUPTSQL); 00500 } 00501 00502 // set up the joined attributes to be passed to Join 00503 qual_attrs[nattrs].relName = first_attr->RelName(); 00504 qual_attrs[nattrs].attrName = first_attr->AttrName(); 00505 qual_attrs[nattrs + 1].relName = second_attr->RelName(); 00506 qual_attrs[nattrs + 1].attrName = second_attr->AttrName(); 00507 00508 for(int acnt = 0; acnt < nattrs; acnt++) 00509 { 00510 strcpy(attrList[acnt].relName, qual_attrs[acnt].relName); 00511 strcpy(attrList[acnt].attrName, qual_attrs[acnt].attrName); 00512 attrList[acnt].attrType = -1; 00513 attrList[acnt].attrLen = -1; 00514 attrList[acnt].attrValue = NULL; 00515 } 00516 00517 strcpy(attr1.relName, qual_attrs[nattrs].relName); 00518 strcpy(attr1.attrName, qual_attrs[nattrs].attrName); 00519 attr1.attrType = -1; 00520 attr1.attrLen = -1; 00521 attr1.attrValue = NULL; 00522 00523 strcpy(attr2.relName, qual_attrs[nattrs+1].relName); 00524 strcpy(attr2.attrName, qual_attrs[nattrs+1].attrName); 00525 attr2.attrType = -1; 00526 attr2.attrLen = -1; 00527 attr2.attrValue = NULL; 00528 00529 // make the call to Operators::Join 00530 00531 Operators::Join(resultName, nattrs, attrList, &attr1, (Operator)(singlepred->Oper()), &attr2); 00532 } 00533 00534 if (resultName == string( "TMP_BDB")) 00535 { 00536 // Print the contents of the result relation and destroy it 00537 Utilities::Print(resultName); 00538 00539 relCat->destroyRel(resultName); 00540 } 00541 00542 00543 return; 00544 } 00545 00546 00547 static int mk_attr_descrs(PxxList *list, ATTR_DESCR attr_descrs[]) 00548 { 00549 int i; 00550 // int type, len; 00551 ListNode *attrlist = list->Init(); 00552 PxxAttrType *attr; 00553 // int errval; 00554 00555 // for each element of the list... 00556 for(i = 0; 00557 attrlist != NULL && i < MAXATTRS; 00558 ++i, attrlist = attrlist->Next()) 00559 { 00560 attr = (PxxAttrType*)(attrlist->Data()); 00561 00562 // add it to the list 00563 attr_descrs[i].attrName = attr->AttrName(); 00564 attr_descrs[i].attrType = attr->Type(); 00565 switch(attr->Type()){ 00566 00567 case PxxAttrType::STRING: 00568 attr_descrs[i].attrLen = attr->Param1(); 00569 // cout << "Length is " << attr->Param1() << endl; 00570 break; 00571 case PxxAttrType::INTEGER: 00572 attr_descrs[i].attrLen = sizeof(int); 00573 break; 00574 case PxxAttrType::DOUBLE: 00575 attr_descrs[i].attrLen = sizeof(double); 00576 break; 00577 } 00578 } 00579 // if the list is too long, then error 00580 if (i == MAXATTRS) 00581 return E_TOOMANYATTRS; 00582 00583 return i; 00584 } 00585 00586 // 00587 // mk_ins_attrs: converts a list of <attribute, value> pairs to an array 00588 // of ATTR_VAL's so it can be sent to Updates::Insert. 00589 // 00590 // Returns: 00591 // length of the list on success ( >= 0 ) 00592 // error code otherwise ( < 0 ) 00593 // 00594 00595 static int mk_ins_attrs(PxxPnode *list, ATTR_VAL ins_attrs[]) 00596 { 00597 int i, type, len; 00598 PxxInsert* insertlist = (PxxInsert*)list; 00599 00600 ListNode *attrlist = insertlist->OptList()->Init(); 00601 ListNode *valuelist = insertlist->ValList()->Init(); 00602 PxxAttrName* attr; 00603 PxxLiteral* literal; 00604 00605 // add the attributes to the list 00606 for(i = 0; 00607 attrlist != NULL && i < MAXATTRS; 00608 ++i, attrlist = attrlist->Next(), valuelist = valuelist->Next()) 00609 { 00610 attr = (PxxAttrName*)(attrlist->Data()); 00611 literal = (PxxLiteral*)(valuelist->Data()); 00612 00613 AttrDesc attrDesc; 00614 00615 attrCat->getInfo(insertlist->RelName(), attr->AttrName(), attrDesc); 00616 00617 // make sure string attributes aren't too long 00618 type = attrDesc.attrType; 00619 len = attrDesc.attrLen; 00620 00621 if (type != literal->LiteralType()) 00622 { 00623 print_error("Value List Corrupt ", E_LITERALTYPE); 00624 return -1; 00625 } 00626 00627 switch(type) 00628 { 00629 00630 case PxxAttrType::STRING: 00631 ins_attrs[i].value = (void*)(literal->Char()); 00632 break; 00633 case PxxAttrType::INTEGER: 00634 ins_attrs[i].value = (void*)(literal->Int()); 00635 break; 00636 case PxxAttrType::DOUBLE: 00637 ins_attrs[i].value = (void*)(literal->Double()); 00638 break; 00639 } 00640 00641 if (type == PxxAttrType::STRING){ 00642 if(len > MAXSTRINGLEN){ 00643 00644 return E_STRINGTOOLONG; 00645 } 00646 } 00647 ins_attrs[i].attrName = attr->AttrName(); 00648 ins_attrs[i].valType = type; 00649 ins_attrs[i].valLength = len; 00650 } 00651 00652 if (attrlist) return E_TOOMANYATTRS; 00653 00654 return i; 00655 } 00656 00657 // 00658 // mk_attrnames: converts a list of qualified attributes (<relation, 00659 // attribute> pairs) into an array of char pointers so it can be 00660 // sent to the appropriate Utilities or Operators function. 00661 // 00662 // All of the attributes should come from relation relname. If relname 00663 // is NULL, then it checks that all attributes come from the same 00664 // relation. 00665 // 00666 // The first element of the array after the last attribute name is 00667 // set to the name of the relation. 00668 // 00669 // Returns: 00670 // the length of the list on success ( >= 0 ) 00671 // error code otherwise ( < 0 ) 00672 // 00673 // (Thus, the return code is both the number of attributes in the array, 00674 // and the index of the relatin name in the array). 00675 // 00676 00677 static int mk_attrnames(PxxList *list, char *attrnames[], char *relname) 00678 { 00679 int i; 00680 ListNode *temp = list->Init(); 00681 PxxAttrName *attr; 00682 00683 // for each qualified attribute in the list... 00684 for(i = 0; temp != NULL && i < MAXATTRS; ++i, temp = temp->Next()) 00685 { 00686 00687 attr = (PxxAttrName*)(temp->Data()); 00688 00689 // if relname is NULL, then remember this relname 00690 if (relname == NULL) 00691 relname = attr->RelName(); 00692 00693 // otherwise, see if the relname matches the remembered relname 00694 else if (strcmp(relname, attr->RelName())) 00695 return E_INCOMPATIBLE; 00696 00697 // add attribute name to the list 00698 attrnames[i] = attr->AttrName(); 00699 } 00700 00701 // if the list is too long then error 00702 if (i == MAXATTRS) 00703 return E_TOOMANYATTRS; 00704 00705 // put the relation name in the last position in the array 00706 attrnames[i] = relname; 00707 00708 return i; 00709 } 00710 00711 00712 // 00713 // mk_qual_attrs: converts a list of qualified attributes (<relation, 00714 // attribute> pairs) into an array of REL_ATTRS so it can be sent to 00715 // Operators::Join. 00716 // 00717 // All of the attributes must come from either relname1 or relname2. 00718 // 00719 // Returns: 00720 // the lengh of the list on success ( >= 0 ) 00721 // error code otherwise 00722 // 00723 00724 static int mk_qual_attrs(PxxList *list, REL_ATTR qual_attrs[], 00725 char *relname1, char *relname2) 00726 { 00727 int i; 00728 ListNode *temp = list->Init(); 00729 PxxAttrName* attr; 00730 00731 // for each element of the list... 00732 for(i = 0; temp != NULL && i < MAXATTRS; ++i, temp = temp->Next()) 00733 { 00734 attr = (PxxAttrName*)(temp->Data()); 00735 00736 // if relname != relname 1... 00737 if (strcmp(attr->RelName(), relname1)) 00738 { 00739 // and relname != relname 2, then error 00740 if (strcmp(attr->RelName(), relname2)) 00741 return E_INCOMPATIBLE; 00742 } 00743 00744 // add it to the list 00745 qual_attrs[i].relName = attr->RelName(); 00746 qual_attrs[i].attrName = attr->AttrName(); 00747 } 00748 00749 // If the list is too long then error 00750 if (i == MAXATTRS) 00751 return E_TOOMANYATTRS; 00752 00753 return i; 00754 } 00755 00756 static void print_error(const char *errmsg, int errval) 00757 { 00758 if (errmsg != NULL) 00759 fprintf(stderr, "%s: ", errmsg); 00760 switch(errval) { 00761 case E_OK: 00762 fprintf(ERRFP, "no error\n"); 00763 break; 00764 case E_INCOMPATIBLE: 00765 fprintf(ERRFP, "attributes must be from selected relation(s)\n"); 00766 break; 00767 case E_TOOMANYATTRS: 00768 fprintf(ERRFP, "too many attributes\n"); 00769 break; 00770 case E_NOLENGTH: 00771 fprintf(ERRFP, "length must be specified for STRING attribute\n"); 00772 break; 00773 case E_INVINTSIZE: 00774 fprintf(ERRFP, "invalid size for INTEGER attribute (should be %d)\n", 00775 sizeof(int)); 00776 break; 00777 case E_INVFLOATSIZE: 00778 fprintf(ERRFP, "invalid size for FLOAT attribute (should be %d)\n", 00779 sizeof(float)); 00780 break; 00781 case E_INVFORMATSTRING: 00782 fprintf(ERRFP, "invalid format string\n"); 00783 break; 00784 case E_INVSTRLEN: 00785 fprintf(ERRFP, "invalid length for string attribute\n"); 00786 break; 00787 case E_DUPLICATEATTR: 00788 fprintf(ERRFP, "duplicated attribute name\n"); 00789 break; 00790 case E_TOOLONG: 00791 fprintf(stderr, "relation name or attribute name too long\n"); 00792 break; 00793 case E_STRINGTOOLONG: 00794 fprintf(stderr, "string attribute too long\n"); 00795 break; 00796 case E_CORRUPTSQL: 00797 fprintf(stderr, "Invalid SQL Statement\n"); 00798 break; 00799 case E_LITERALTYPE: 00800 fprintf(stderr, "Data Type Mistmatch\n"); 00801 break; 00802 default: 00803 fprintf(ERRFP, "unrecognized errval: %d\n", errval); 00804 } 00805 } 00806