const Status RelCatalog::createRel(const string & relation, const int attrCnt, const attrInfo attrList[]) { Status status; RelDesc rd; AttrDesc ad; int offset; if (relation.empty() || attrCnt < 1) return BADCATPARM; if (relation.length() >= sizeof rd.relName) return NAMETOOLONG; //check to see if relation already exisits status = relCat->getInfo(relation, rd); if(status == OK) { return RELEXISTS; } //initializing the RelDesc and adding it to relCat memcpy(rd.relName, relation.c_str(),sizeof(rd.relName)); rd.attrCnt = attrCnt; status = relCat->addInfo(rd); if (status != OK) return status; offset = 0; //copy the attr data into the AttrDesc struct, and add to attrCat for(int i = 0; i < attrCnt; i++){ strcpy(ad.relName, attrList[i].relName); strcpy(ad.attrName, attrList[i].attrName); ad.attrType = attrList[i].attrType; ad.attrLen = attrList[i].attrLen; ad.attrOffset = offset; status = attrCat->addInfo(ad); if(status != OK) return status; //add offset for next attribute offset = (offset + attrList[i].attrLen); } //create the heapFile instance to hold tuples for this relation status = createHeapFile(relation); return status; }
const Status RelCatalog::createRel(const string & relation, const int attrCnt, const attrInfo attrList[]) { Status status; RelDesc rd; int offset = 0; if (relation.empty() || attrCnt < 1) return BADCATPARM; if (relation.length() >= sizeof rd.relName) return NAMETOOLONG; for (int i = 0; i < attrCnt; i++) { for (int j = i + 1; j < attrCnt; j++) { if (strncmp(attrList[i].attrName, attrList[j].attrName, 32) == 0) { return DUPLATTR; } } } status = getInfo(relation, rd); if (status == OK) { return RELEXISTS; } else if (status != RELNOTFOUND) { return status; } rd.attrCnt = attrCnt; strncpy(rd.relName,relation.c_str(),min(relation.length(), (size_t) MAXNAME - 1)); if (RelCatalog::addInfo(rd) != OK) { return status; } for (int i = 0; i < attrCnt; i++) { AttrDesc ad; ad.attrLen = attrList[i].attrLen; strncpy(ad.attrName,attrList[i].attrName,32); ad.attrType = attrList[i].attrType; ad.attrOffset = offset; offset += ad.attrLen; strncpy(ad.relName, attrList[i].relName,32); status = attrCat->addInfo(ad); if (status != OK) { return status; } } return createHeapFile(relation); }
/** * FUNCTION: RelCatalog::createRel * * PURPOSE: Creates a new relation in current database * * PARAMETERS: * relation (in) Relation name to be created * attrCnt (in) Number of attributes in the relation * attrList (in) Information of all the attributes * * RETURN VALUES: * Status OK Relation successfully created. * BADCATPARM Relation name is empty * NAMETOOLONG Relation name too long * RELEXISTS A relation with the same name already exists * FILEEOF Reached the end of file while scanning for the record * BUFFEREXCEEDED All buffer frames are pinned * HASHTBLERROR Hash table error occurred * PAGENOTPINNED Pin count is already 0 * HASHNOTFOUND Page is not in the buffer pool hash table **/ const Status RelCatalog::createRel(const string & relation, const int attrCnt, const attrInfo attrList[]) { Status status; RelDesc rd; AttrDesc ad; if (relation.empty() || attrCnt < 1) return BADCATPARM; if (relation.length() >= sizeof rd.relName) return NAMETOOLONG; status = relCat->getInfo(relation, rd); if(status == OK) { return RELEXISTS; } else { // Adding a tuple in "relcat" table strcpy(rd.relName, relation.c_str()); rd.attrCnt = attrCnt; status = addInfo(rd); // Adding appropriate tuples in the "attrcat" table int offset = 0; for(int i = 0; i< attrCnt; i++) { strcpy(ad.relName, attrList[i].relName); strcpy(ad.attrName, attrList[i].attrName); ad.attrOffset = offset;//(i == 0) ? 0 : MAXNAME; ad.attrType = attrList[i].attrType; ad.attrLen = attrList[i].attrLen; offset += ad.attrLen; status = attrCat->addInfo(ad); if(status != OK) break; } } // Creating HeapFile for the relation status = createHeapFile(relation.c_str()); return status; }
int main(int argc, char **argv) { cout << "Testing the relation interface" << endl << endl; // DB db; Error error; HeapFile* file1; HeapFileScan *scan1, *scan2; InsertFileScan *iScan; Status status; RID newRid; int deleted; typedef struct { int i; float f; char s[64]; } RECORD; RECORD rec1; RECORD rec2; // retrieved recs are unaligned!! int rec1Len; Record dbrec2; RID rec2Rid; bufMgr = new BufMgr(101); int i,j; int num = 10120; Record dbrec1; RID* ridArray; ridArray = new RID[num]; // destroy any old copies of "dummy.02" status = destroyHeapFile("dummy.02"); // ignore the error return status = createHeapFile("dummy.02"); if (status != OK) { cerr << "got err0r status return from createHeapFile" << endl; error.print(status); } // initialize all of rec1.s to keep purify happy memset(rec1.s, ' ', sizeof(rec1.s)); cout << endl; cout << "insert " << num << " records into dummy.02" << endl; cout << endl; cout << "Start an insert scan which will have the side effect of opening dummy.02 " << endl; iScan = new InsertFileScan("dummy.02", status); for(i = 0; i < num; i++) { sprintf(rec1.s, "This is record %05d", i); rec1.i = i; rec1.f = i; dbrec1.data = &rec1; dbrec1.length = sizeof(RECORD); status = iScan->insertRecord(dbrec1, newRid); // stash away rid and key of the record ridArray[i] = newRid; //printf("next rid (%d.%d)\n",ridArray[i].pageNo, ridArray[i].slotNo); if (status != OK) { cout << "got err0r status return from insertrecord" << endl; cout << "inserted " << i << "records into file dummy1 before error " << endl; error.print(status); exit(1); } } delete iScan; // delete the scan, closing the file at the same time file1 = NULL; cout << "inserted " << num << " records into file dummy.02 successfully" << endl; cout << endl; cout << endl; cout << "pull 11th record from file dummy.02 using file->getRecord() " << endl; file1 = new HeapFile("dummy.02", status); // open the file if (status != OK) error.print(status); else { // get every record for (i=0;i<num;i=i+11) { // reconstruct record for comparison purposes sprintf(rec1.s, "This is record %05d", i); rec1.i = i; rec1.f = i; // now read the record //printf("getting record (%d.%d)\n",ridArray[i].pageNo, ridArray[i].slotNo); status = file1->getRecord(ridArray[i], dbrec2); if (status != OK) error.print(status); // compare with what we should get back if (memcmp(&rec1, dbrec2.data, sizeof(RECORD)) != 0) cout << "err0r reading record " << i << " back" << endl; } cout << "getRecord() tests passed successfully" << endl; } delete file1; // scan the file sequentially checking that each record was stored properly cout << "scan file dummy.02 " << endl; scan1 = new HeapFileScan("dummy.02", status); if (status != OK) error.print(status); else { scan1->startScan(0, 0, STRING, NULL, EQ); i = 0; while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { // reconstruct record i sprintf(rec1.s, "This is record %05d", i); rec1.i = i; rec1.f = i; status = scan1->getRecord(dbrec2); if (status != OK) break; if (memcmp(&rec1, dbrec2.data, sizeof(RECORD)) != 0) cout << "err0r reading record " << i << " back" << endl; i++; } if (status != FILEEOF) error.print(status); cout << "scan file1 saw " << i << " records " << endl; if (i != num) cout << "Err0r. scan should have returned " << num << " records!" << endl; } // delete scan object scan1->endScan(); delete scan1; scan1 = NULL; // scan the file sequentially checking that each record was stored properly cout << endl << "scan file dummy.02 " << endl; scan1 = new HeapFileScan("dummy.02", status); if (status != OK) error.print(status); else { scan1->startScan(0, 0, STRING, NULL, EQ); i = 0; while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { // reconstruct record i sprintf(rec1.s, "This is record %05d", i); rec1.i = i; rec1.f = i; status = scan1->getRecord(dbrec2); if (status != OK) break; if (memcmp(&rec1, dbrec2.data, sizeof(RECORD)) != 0) cout << "err0r reading record " << i << " back" << endl; i++; } if (status != FILEEOF) error.print(status); cout << "scan file1 saw " << i << " records " << endl; if (i != num) cout << "Err0r. scan should have returned " << num << " records!" << endl; } // delete scan object scan1->endScan(); delete scan1; scan1 = NULL; // pull every 7th record from the file directly w/o opening a scan // by using the file->getRecord() method cout << endl; cout << "pull every 7th record from file dummy.02 using file->getRecord() " << endl; file1 = new HeapFile("dummy.02", status); // open the file if (status != OK) error.print(status); else { // get every 7th record for (i=0;i<num;i=i+7) { // reconstruct record for comparison purposes sprintf(rec1.s, "This is record %05d", i); rec1.i = i; rec1.f = i; // now read the record //printf("getting record (%d.%d)\n",ridArray[i].pageNo, ridArray[i].slotNo); status = file1->getRecord(ridArray[i], dbrec2); if (status != OK) error.print(status); // compare with what we should get back if (memcmp(&rec1, dbrec2.data, sizeof(RECORD)) != 0) cout << "err0r reading record " << i << " back" << endl; } cout << "getRecord() tests passed successfully" << endl; } delete file1; // close the file delete [] ridArray; // next scan the file deleting all the odd records cout << endl; cout << "scan file deleting all records whose i field is odd" << endl; scan1 = new HeapFileScan("dummy.02", status); if (status != OK) error.print(status); else { scan1->startScan(0, 0, STRING, NULL, EQ); i = 0; deleted = 0; while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { // cout << "processing record " << i << i << endl; if (status != OK) error.print(status); if ((i % 2) != 0) { // printf("deleting record %d with rid(%d.%d)\n",i,rec2Rid. pageNo, rec2Rid.slotNo); status = scan1->deleteRecord(); deleted++; if ((status != OK) && ( status != NORECORDS)) { cout << "err0r status return from deleteRecord" << endl; error.print(status); } } i++; } if (status != FILEEOF) error.print(status); cout << "deleted " << deleted << " records" << endl; if (deleted != num / 2) cout << "Err0r. should have deleted " << num / 2 << " records!" << endl; scan1->endScan(); } delete scan1; scan1 = NULL; cout << endl; cout << "scan file, counting number of remaining records" << endl; scan1 = new HeapFileScan("dummy.02", status); if (status != OK) error.print(status); else { i = 0; scan1->startScan(0, 0, STRING, NULL, EQ); while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { if ( i > 0 ) // don't delete the first one { status = scan1->deleteRecord(); if ((status != OK) && ( status != NORECORDS)) { cout << "err0r status return from deleteRecord" << endl; error.print(status); } } i++; } // subtract first record i--; if (status != FILEEOF) error.print(status); scan1->endScan(); delete scan1; scan1 = NULL; scan1 = new HeapFileScan("dummy.02", status); scan1->startScan(0, 0, STRING, NULL, EQ); // delete the rest (should only be one) while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { status = scan1->deleteRecord(); if ((status != OK) && ( status != NORECORDS)) { cout << "err0r status return from deleteRecord" << endl; error.print(status); } i++; } scan1->endScan(); delete scan1; cout << "scan saw " << i << " records " << endl; if (i != (num+1) / 2) cout << "Err0r. scan should have returned " << (num+1) / 2 << " records!" << endl; } status = destroyHeapFile("dummy.02"); if (status != OK) { cerr << "got err0r status return from destroyHeapFile" << endl; error.print(status); } status = createHeapFile("dummy.03"); if (status != OK) { cerr << "got err0r status return from createHeapFile" << endl; error.print(status); } iScan = new InsertFileScan("dummy.03", status); if (status != OK) { cout << "got err0r status return from new insertFileScan call" << endl; error.print(status); } cout << endl; cout << "insert " << num << " variable-size records into dummy.03" << endl; int smallest, largest; for(i = 0; i < num; i++) { rec1Len = 2 + rand() % (sizeof(rec1.s)-2); // includes NULL!! //cout << "record length is " << rec1Len << endl; memset((void *)rec1.s, 32 + rec1Len, rec1Len - 1); rec1.s[rec1Len-1] = 0; rec1Len += sizeof(rec1.i) + sizeof(rec1.f); rec1.i = i; rec1.f = rec1Len; dbrec1.data = &rec1; dbrec1.length = rec1Len; status = iScan->insertRecord(dbrec1, newRid); if (status != OK) { cout << "got err0r status return from insertrecord" << endl; error.print(status); } if (i == 0 || rec1Len < smallest) smallest = rec1Len; if (i == 0 || rec1Len > largest) largest = rec1Len; } cout << "inserted " << num << " variable sized records successfully into dummy.03" << endl; cout << "smallest record was " << smallest << " bytes, largest was " << largest << " bytes" << endl; delete iScan; file1 = NULL; cout << endl << "scan dummy.03 using the predicate < num/2 " << endl; j = num/2; scan1 = new HeapFileScan("dummy.03", status); if (status != OK) error.print(status); else { scan1->startScan(0, sizeof(int), INTEGER, (char*)&j, LT); i = 0; while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { status = scan1->getRecord(dbrec2); if (status != OK) break; memcpy(&rec2, dbrec2.data, dbrec2.length); if (rec2.i >= j || rec2.f != dbrec2.length || rec2.s[0] != 32+dbrec2.length-8) cout << "err0r reading record " << i << " back" << endl; i++; } if (status != FILEEOF) error.print(status); cout << "scan of dummy.03 saw " << i << " records " << endl; if (i != num / 2) cout << "Err0r. scan should have returned " << num / 2 << " records!" << endl; } scan1->endScan(); delete scan1; scan1 = NULL; //================================================ cout << endl; cout << "Next attempt two concurrent scans on dummy.03 " << endl; int Ioffset = (int)((char*)&rec1.i - (char*)&rec1); int Ivalue = num/2; int Foffset = (int)((char*)&rec1.f - (char*)&rec1); float Fvalue = 0; scan1 = new HeapFileScan("dummy.03", status); if (status != OK) error.print(status); status = scan1->startScan(Ioffset, sizeof(int), INTEGER, (char*)&Ivalue, LT); if (status != OK) error.print(status); scan2 = new HeapFileScan("dummy.03", status); if (status != OK) error.print(status); status = scan2->startScan(Foffset, sizeof(float), FLOAT, (char*)&Fvalue, GTE); if (status != OK) error.print(status); else { int count = 0; for(i = 0; i < num; i++) { status = scan1->scanNext(rec2Rid); if (status == OK) count++; else if (status != FILEEOF) error.print(status); status = scan2->scanNext(rec2Rid); if (status == OK) count++; else if (status != FILEEOF) error.print(status); } cout << "scan file1 saw " << count << " records " << endl; if (count != num/2 + num) cout << "Err0r. scan should have returned " << num/2 + num << " records!" << endl; if (scan1->scanNext(rec2Rid) != FILEEOF) cout << "Err0r. scan past end of file did not return FILEEOF!" << endl; if (scan2->scanNext(rec2Rid) != FILEEOF) cout << "Err0r. scan past end of file did not return FILEEOF!" << endl; } delete scan1; delete scan2; scan1 = scan2 = NULL; cout << endl; cout << "Destroy dummy.03" << endl; if ((status = destroyHeapFile("dummy.03")) != OK) { cout << "got err0r status return from destroy file" << endl; error.print(status); } status = createHeapFile("dummy.04"); if (status != OK) { cerr << "got err0r status return from createHeapFile" << endl; error.print(status); } iScan = new InsertFileScan("dummy.04", status); if (status != OK) { cerr << "got err0r status return from new insertFileScan" << endl; error.print(status); } cout << "inserting " << num << " records into dummy1" << endl; for(i = 0; i < num; i++) { sprintf(rec1.s, "This is record %05d", i); rec1.i = i; rec1.f = i; dbrec1.data = &rec1; dbrec1.length = sizeof(RECORD); status = iScan->insertRecord(dbrec1, newRid); if (status != OK) { cout << "got err0r status return from insertrecord" << endl; error.print(status); } } delete iScan; file1 = NULL; //bufMgr->clearBufStats(); int numDeletes = 0; cout << endl; cout << "now scan dummy.04, deleting records with keys between 1000 and 2000" << endl; scan1 = new HeapFileScan("dummy.04", status); if (status != OK) error.print(status); status = scan1->startScan(0, 0, STRING, NULL, EQ); if (status != OK) error.print(status); else { i = 0; while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { // reconstruct record i sprintf(rec1.s, "This is record %05d", i); rec1.i = i; rec1.f = i; status = scan1->getRecord(dbrec2); if (status != OK) break; if (memcmp(&rec1, dbrec2.data, sizeof(RECORD)) != 0) cout << "err0r reading record " << i << " back" << endl; if ((i > 1000) && ( i <= 2000)) { status = scan1->deleteRecord(); if ((status != OK) && ( status != NORECORDS)) { cout << "err0r status return from deleteRecord" << endl; error.print(status); } else numDeletes++; } i++; } if (status != FILEEOF) error.print(status); cout << "scan file1 saw " << i << " records " << endl; if (i != num) cout << "Err0r. scan should have returned " << (int) num << " records!!" << endl; cout << "number of records deleted by scan " << numDeletes << endl; if (numDeletes != 1000) cout << "Err0r. Should have deleted 1000 records!!!" << endl; } cout << endl; delete scan1; // rescan. should see 1000 fewer records scan1 = new HeapFileScan("dummy.04", status); if (status != OK) error.print(status); scan1->startScan(0, 0, STRING, NULL, EQ); i = 0; while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { i++; } cout << "should have seen 1000 fewer records after deletions" << endl; cout << "saw " << i << "records" << endl; delete scan1; // perform filtered scan #1 scan1 = new HeapFileScan("dummy.04", status); if (status != OK) error.print(status); int filterVal1 = num * 3 / 4; cout << endl << "Filtered scan matching i field GTE than " << filterVal1 << endl; status = scan1->startScan(0, sizeof(int), INTEGER, (char *) &filterVal1, GTE); if (status != OK) { cerr << "got err0r status return from startScan" << endl; error.print(status); } else { // do scan i = 0; while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { // reconstruct record i status = scan1->getRecord(dbrec2); if (status != OK) break; // verify that the scan predicate was actually met RECORD *currRec = (RECORD *) dbrec2.data; if (! (currRec->i >= filterVal1)) { cerr << "Err0r. filtered scan returned record that doesn't satisfy predicate " << "i val is " << currRec->i << endl; exit(1); } i++; } if (status != FILEEOF) error.print(status); cout << "scan file1 saw " << i << " records " << endl; if (i != num/4) cout << "Err0r. scan should have returned " << num/4 << " records!" << " returned "<< i <<endl; } delete scan1; // perform filtered scan #2 scan1 = new HeapFileScan("dummy.04", status); if (status != OK) error.print(status); // perform filtered scan #2 float filterVal2 = num * 9 / 10; cout << endl << "Filtered scan matching f field GT than " << filterVal2 << endl; status = scan1->startScan(sizeof(int), sizeof(float), FLOAT, (char *) &filterVal2, GT); if (status != OK) { cerr << "got err0r status return from startScan" << endl; error.print(status); } else { // do scan i = 0; while ((status = scan1->scanNext(rec2Rid)) != FILEEOF) { // reconstruct record i status = scan1->getRecord(dbrec2); if (status != OK) break; // verify that the scan predicate was actually met RECORD *currRec = (RECORD *) dbrec2.data; if (! (currRec->f > filterVal2)) { cerr << "Err0r. filtered scan returned record that doesn't satisfy predicate " << "f val is " << currRec->f << endl; exit(1); } // cout << "scan return: " << currRec->f << endl; i++; } if (status != FILEEOF) error.print(status); cout << "scan file1 saw " << i << " records " << endl; if (i != num/10-1) cout << "Err0r. filtered scan 2 should have returned " << num/10-1 << " records!" << endl; } delete scan1; // open up the heapFile file1 = new HeapFile("dummy.04", status); if (status != OK) { cerr << "got err0r status return from new HeapFile" << endl; error.print(status); } delete file1; // cout << "BUFSTATS:" << bufMgr->getBufStats() << endl; // bufMgr->clearBufStats(); scan1 = new HeapFileScan("dummy.04", status); if (status != OK) error.print(status); status = scan1->startScan(0, 20, INTEGER, "Hi" , EQ); if ( status == BADSCANPARM) { cout << endl << "passed BADSCANPARAM test" << endl; } else { cout << "should have returned BADSCANPARM, actually returned: " << endl; error.print(status); } // add insert for bigger than pagesized record iScan = new InsertFileScan("dummy.04", status); if (status != OK) error.print(status); char bigdata[8192]; sprintf(bigdata, "big record"); dbrec1.data = (void *) &bigdata; dbrec1.length = 8192; status = iScan->insertRecord(dbrec1, rec2Rid); if ((status == INVALIDRECLEN) || (status == NOSPACE)) { cout << endl << "passed large record insert test" << endl; } else { cout << "got err0r status return from insert record " << endl; error.print(status); cout << "expected INVALIDRECLEN or NOSPACE" << endl; } delete iScan; delete scan1; // MORE ERROR HANDLING TESTS HERE // get rid of the file if ((status = destroyHeapFile("dummy.04")) != OK) { cout << endl << "got err0r status return from destroy file" << endl; error.print(status); } delete bufMgr; cout << endl << "Done testing." << endl; return 1; }
const Status RelCatalog::createRel(const string & relation, const int attrCnt, const attrInfo attrList[]) { Status status; RelDesc rd; AttrDesc ad; if (relation.empty() || attrCnt < 1) return BADCATPARM; if (relation.length() >= sizeof rd.relName) return NAMETOOLONG; // make sure the relation doesn't already exist status = getInfo(relation, rd); if (status == OK) return RELEXISTS; if (status != RELNOTFOUND) return status; // make sure there are no duplicate attribute names unsigned int tupleWidth = attrList[0].attrLen; if (attrCnt > 1) { for(int i = 1; i < attrCnt; i++) { tupleWidth += attrList[i].attrLen; for(int j = 0; j < i; j++) if (strcmp(attrList[i].attrName, attrList[j].attrName) == 0) return DUPLATTR; } } if (tupleWidth > PAGESIZE) // should be more strict return ATTRTOOLONG; cout << "Creating relation " << relation << endl; // insert information about relation strcpy(rd.relName, relation.c_str()); rd.attrCnt = attrCnt; if ((status = addInfo(rd)) != OK) return status; // insert information about attributes strcpy(ad.relName, relation.c_str()); int offset = 0; for(int i = 0; i < attrCnt; i++) { if (strlen(attrList[i].attrName) >= sizeof ad.attrName) return NAMETOOLONG; strcpy(ad.attrName, attrList[i].attrName); ad.attrOffset = offset; ad.attrType = attrList[i].attrType; ad.attrLen = attrList[i].attrLen; if ((status = attrCat->addInfo(ad)) != OK) { cout << "got error return" << status << endl; return status; } offset += ad.attrLen; } // now create the actual heapfile to hold the relation status = createHeapFile (relation); if (status != OK) return status; return OK; }
int main(int argc, char *argv[]) { if (argc < 2) { cerr << "Usage: " << argv[0] << " dbname" << endl; return 1; } // create database subdirectory and chdir there if (mkdir(argv[1], S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP) < 0) { perror("mkdir"); exit(1); } if (chdir(argv[1]) < 0) { perror("chdir"); exit(1); } // create buffer manager bufMgr = new BufMgr(100); Status status; // create heapfiles to hold the relcat and attribute catalogs status = createHeapFile("relcat"); if (status != OK) { error.print(status); exit(1); } status = createHeapFile("attrcat"); if (status != OK) { error.print(status); exit(1); } // open relation and attribute catalogs relCat = new RelCatalog(status); if (status == OK) attrCat = new AttrCatalog(status); if (status != OK) { error.print(status); exit(1); } // add tuples describing relcat and attrcat to relation catalog // and attribute catalog RelDesc rd; AttrDesc ad; strcpy(rd.relName, RELCATNAME); rd.attrCnt = 2; CALL(relCat->addInfo(rd)); strcpy(ad.relName, RELCATNAME); strcpy(ad.attrName, "relName"); ad.attrOffset = 0; ad.attrType = (int)STRING; ad.attrLen = sizeof rd.relName; CALL(attrCat->addInfo(ad)); strcpy(ad.attrName, "attrCnt"); ad.attrOffset += sizeof rd.relName; ad.attrType = (int)INTEGER; ad.attrLen = sizeof rd.attrCnt; CALL(attrCat->addInfo(ad)); strcpy(rd.relName, ATTRCATNAME); rd.attrCnt = 5; CALL(relCat->addInfo(rd)) strcpy(ad.relName, ATTRCATNAME); strcpy(ad.attrName, "relName"); ad.attrOffset = 0; ad.attrType = (int)STRING; ad.attrLen = sizeof ad.relName; CALL(attrCat->addInfo(ad)); strcpy(ad.attrName, "attrName"); ad.attrOffset += sizeof ad.relName; ad.attrType = (int)STRING; ad.attrLen = sizeof ad.attrName; CALL(attrCat->addInfo(ad)); strcpy(ad.attrName, "attrOffset"); ad.attrOffset += sizeof ad.attrName; ad.attrType = (int)INTEGER; ad.attrLen = sizeof ad.attrOffset; CALL(attrCat->addInfo(ad)); strcpy(ad.attrName, "attrType"); ad.attrOffset += sizeof ad.attrOffset; ad.attrType = (int)INTEGER; ad.attrLen = sizeof ad.attrType; CALL(attrCat->addInfo(ad)); strcpy(ad.attrName, "attrLen"); ad.attrOffset += sizeof ad.attrType; ad.attrType = (int)INTEGER; ad.attrLen = sizeof ad.attrLen; CALL(attrCat->addInfo(ad)); delete relCat; delete attrCat; delete bufMgr; cout << "Database " << argv[1] << " created" << endl; return 0; }