Status Operators::IndexSelect(const string& result, // Name of the output relation const int projCnt, // Number of attributes in the projection const AttrDesc projNames[], // Projection list (as AttrDesc) const AttrDesc* attrDesc, // Attribute in the selection predicate const Operator op, // Predicate operator const void* attrValue, // Pointer to the literal value in the predicate const int reclen) // Length of a tuple in the output relation { cout << "Algorithm: Index Select" << endl; /* Your solution goes here */ Status Stat; HeapFile heapfile = HeapFile(result, Stat); if(Stat != OK) { cerr << "Open heap file fail" << endl; return Stat; } string relation = projNames[0].relName; int unique = 0; RID rid; Record record; Record tuple; //Open index file Index indScan(relation, attrDesc->attrOffset, attrDesc->attrLen, (Datatype)attrDesc->attrType, unique, Stat); if(Stat != OK){ return Stat; } //Heapscan object to access the getRandomRecord() function HeapFileScan heapScan=HeapFileScan(relation,attrDesc->attrOffset, attrDesc->attrLen,(Datatype)(attrDesc->attrType),(char *)attrValue,op,Stat); if(Stat != OK){ return Stat; } //Start Index Scan Stat = indScan.startScan(attrValue); while(indScan.scanNext(rid)==OK){ heapScan.getRandomRecord(rid,record); tuple.length = reclen; tuple.data = malloc(reclen); int offset = 0; //Project record for(int i=0; i<projCnt; ++i){ memcpy((char*)tuple.data + offset, (char*)record.data + projNames[i].attrOffset, projNames[i].attrLen); offset += projNames[i].attrLen; } Stat = heapfile.insertRecord(tuple, rid); free(tuple.data); if(Stat != OK){ return Stat; } } indScan.endScan(); heapScan.endScan(); return OK; }
HeapFile *SortFile(HeapFile *S, int len, int offset) { Status s; Scan *scan; scan = S->OpenScan(s); if (s != OK) { cerr << "ERROR : cannot open scan on the heapfile to sort.\n"; } // // Scan the HeapFile S, new a B+Tree and insert the records into B+Tree. // BTreeFile *btree; btree = new BTreeFile (s, "BTree", ATTR_INT, sizeof(int)); char *recPtr = new char[len]; int recLen = len; RecordID rid; while (scan->GetNext(rid, recPtr, recLen) == OK) { btree->Insert(recPtr + offset, rid); } delete scan; HeapFile *sorted; sorted = new HeapFile(NULL, s); // create a temp HeapFile if (s != OK) { cerr << "Cannot create new file for sortedS\n"; } // // Now scan the B+-Tree and insert the records into a // new (sorted) HeapFile. // BTreeFileScan *btreeScan; btreeScan = (BTreeFileScan *)btree->OpenScan(NULL, NULL); int key; while (btreeScan->GetNext(rid, &key) == OK) { S->GetRecord (rid, recPtr, recLen); sorted->InsertRecord (recPtr, recLen, rid); } btree->DestroyFile(); delete btree; delete btreeScan; delete [] recPtr; return sorted; }
//------------------------------------------------------------------- // Sort::MergeManyToOne // // Input : numSourceFiles, number of files needed to be merged // source, array of heap files to be merged // dest, output heap file // Output : None // Return : OK if merging succeeds, FAIL otherwise //------------------------------------------------------------------- Status Sort::MergeManyToOne(unsigned int numSourceFiles, HeapFile **source, HeapFile *dest) { // Open a scan for each source file Status status; int numOfRecords = 0, recCounter = 0; Scan **scanners = new Scan *[numSourceFiles]; RecordID rid; char *recPtr = (char *)malloc(_recLength); int recLen = _recLength; for (int i=0; i<numSourceFiles; i++) { HeapFile *hf = source[i]; Scan *scan = hf->OpenScan(status); if (status != OK) return ReturnFAIL("Opening scanners in MergeManyToOne failed."); scanners[i] = scan; numOfRecords += hf->GetNumOfRecords(); } // Create a vector to hold (numSourceFiles) records to compare std::vector<std::tuple<char *, int>> values; char **recPtrArray = new char*[numSourceFiles]; for (int i=0; i<numSourceFiles; i++) { if (scanners[i]->GetNext(rid,recPtr,recLen) != OK) return ReturnFAIL("Error scanning files in MergeManyToOne"); recPtrArray[i] = (char *)malloc(recLen); memcpy(recPtrArray[i],recPtr,recLen); values.push_back(std::make_tuple(recPtrArray[i],i)); } while (recCounter < numOfRecords) { // merge till all records are written out std::sort(values.begin(),values.end(),&CompareForMerge); // sort vector std::tuple<char *,int> first = values.front(); // get smallest/largest in vector int firstIndex = std::get<1>(first); dest->InsertRecord(std::get<0>(first),recLen,rid); // add it to output file recCounter++; status = scanners[firstIndex]->GetNext(rid,recPtr,recLen); // try to move pointer if (status == FAIL) return ReturnFAIL("Error scanning files in MergeManyToOne"); else if (status == OK) { // if there are still records in that file memcpy(recPtrArray[firstIndex],recPtr,recLen); values.push_back(std::make_tuple(recPtrArray[firstIndex],firstIndex)); // add new record to vector } values.erase(values.begin()); // erase first } free(recPtr); for (int i=0;i<numSourceFiles; i++) { delete scanners[i]; } for (int i=0;i<numSourceFiles;i++) { free(recPtrArray[i]); } delete scanners; delete recPtrArray; return OK; }
//------------------------------------------------------------- // test //------------------------------------------------------------- Status test(int t) { char outfile[10]; int Rarray[] = { 0, 1, 0, 3, 4, 4, 4 }; int Sarray[] = { 1, 0, 2, 2, 2, 3, 0 }; int R = Rarray[t-1]; int S = Sarray[t-1]; Status s; sprintf(outfile,"test%d", t); // Perform sort-merge on R and S sortMerge sm(files[R],NUM_COLS,attrType,attrSize,JOIN_COL,files[S],NUM_COLS,attrType,attrSize,JOIN_COL,outfile,SORTPGNUM,Ascending,s); if (s != OK) { cout << "Test " << t << " -- sortMerge failed" << endl; return s; } // Write merged results to stdout HeapFile* outf = new HeapFile (outfile,s); if (s != OK) { cout << "Test " << t << " -- result file not created " << endl; return s; } Scan* scan = outf->openScan(s); assert(s == OK); int len; RID rid; char rec[sizeof(struct _rec)*2]; cout << endl; cout << "------------ Test " << t << " ---------------" << endl; for (s = scan->getNext(rid, rec, len); s == OK; s = scan->getNext(rid, rec, len)) { cout << (*((struct _rec*)&rec)).key << "\t" << (*((struct _rec*)&rec[8])).key << endl; } cout << "-------- Test " << t << " completed --------" << endl; delete scan; s=outf->deleteFile(); if(s!=OK) MINIBASE_CHAIN_ERROR(JOINS,s); delete outf; return s; }
//------------------------------------------------------------- // createFiles //------------------------------------------------------------- void createFiles() { struct _rec rec; memcpy(rec.filler," ",4); for (int i=0; i< NUMFILES; i++) { Status s; RID rid; HeapFile* f = new HeapFile(files[i],s); if (s != OK) cout<<"this is ridiculous !"<<endl; for (int j=0; j<dsize[i]; j++) { rec.key = data[i][j]; s = f->insertRecord((char*)&rec,sizeof(rec),rid); if (s != OK) cout<<"this is ridiculous !"<<endl; } delete f; } }
//-------------------------------------------------------------------- // JoinMethod::SortFile // // Purpose : Sorts a relation by an integer attribute. // Input : file - pointer to the HeapFile to be sorted. // len - length of the records in the file. (assume fixed size). // offset - offset of the sort attribute from the beginning of the record. // Method : We create a B+-Tree using that attribute as the key. Then // we scan the B+-Tree and insert the records into a new // HeapFile. he HeapFile guarantees that the order of // insertion will be the same as the order of scan later. // Return : The new sorted relation/HeapFile. //-------------------------------------------------------------------- HeapFile* JoinMethod::SortHeapFile(HeapFile *file, int len, int offset) { Status s; Scan *scan; scan = file->OpenScan(s); if (s != OK) { std::cerr << "ERROR : cannot open scan on the heapfile to sort." << std::endl; } // // Scan the HeapFile S, create a new B+Tree and insert the records into B+Tree. // BTreeFile *btree; btree = new BTreeFile (s, "BTree"); char* recPtr = new char[len]; int recLen = len; RecordID rid; char* recKey = new char[100]; while (scan->GetNext(rid, recPtr, recLen) == OK) { int* valPtr = (int*)(recPtr+offset); int val = *valPtr; toString(val,recKey); btree->Insert(recKey, rid); } delete scan; delete [] recKey; //std::cout << "created B+ tree!" << std::endl; HeapFile *sorted = new HeapFile(NULL, s); // create a temp HeapFile if (s != OK) { std::cerr << "Cannot create new file for sortedS\n"; } // Now scan the B+-Tree and insert the records into a // new (sorted) HeapFile. BTreeFileScan* btreeScan = btree->OpenScan(NULL, NULL); //int key; char* keyPtr; while (btreeScan->GetNext(rid, keyPtr) == OK) { //std::cout << "scanning " << rid << " " << keyPtr << std::endl; file->GetRecord (rid, recPtr, recLen); sorted->InsertRecord (recPtr, recLen, rid); } btree->DestroyFile(); delete btree; delete btreeScan; delete [] recPtr; return sorted; }
Status Updates::Insert(const string& relation, // Name of the relation const int attrCnt, // Number of attributes specified in INSERT statement const attrInfo attrList[]) // Value of attributes specified in INSERT statement { /* Your solution goes here */ Record record; int TempattrCnt; AttrDesc *attrd; bool insert = true; Status Stat; Stat = attrCat->getRelInfo(relation, TempattrCnt, attrd); if(Stat != OK){ return Stat; } if(TempattrCnt == attrCnt){ //Get length of record and allocate memory for it record.length = attrd[TempattrCnt-1].attrOffset+attrd[TempattrCnt-1].attrLen-attrd[0].attrOffset; record.data = malloc(record.length); //Reorder AttrList attrInfo Tempattrl[TempattrCnt]; for(int i=0; i<TempattrCnt; ++i){ for(int j=0; j<TempattrCnt; ++j){ if(strcmp(attrd[i].attrName, attrList[j].attrName)==0){ Tempattrl[i] = attrList[j]; } } } //Package data into record for(int i =0; i<TempattrCnt;i++){ int len = strlen((char*)Tempattrl[i].attrValue); if((Datatype)Tempattrl[i].attrType==2 && len>attrd[i].attrLen){ insert = false; }else{ memcpy((char*)record.data+attrd[i].attrOffset, Tempattrl[i].attrValue, attrd[i].attrLen); } } //Insert Data Entry into Heapfile Status openHeapStat, insertHeapStat, openIndexStat, insertIndexStat; RID recordId; int unique = 0; Datatype type; //Utilities U;//for insert test HeapFile tempHeap = HeapFile(relation, openHeapStat); if(openHeapStat == OK && insert){ //insert record into heapfile and release memory insertHeapStat = tempHeap.insertRecord(record, recordId); //U.Print(relation);//for insert test free(record.data); if(insertHeapStat == OK){ for (int i=0; i< TempattrCnt; ++i){ if(attrd[i].indexed==1){ type = (Datatype)attrd[i].attrType; Index index = Index(relation, attrd[i].attrOffset, attrd[i].attrLen,type, unique, openIndexStat); if (openIndexStat == OK){ insertIndexStat = index.insertEntry(Tempattrl[i].attrValue,recordId); }else{ delete []attrd; return openIndexStat; } } } }else{ delete []attrd; return insertHeapStat; } }else{ free(record.data); if(!insert){ delete []attrd; return ATTRTOOLONG; }else{ delete []attrd; return openHeapStat; } } }else{ delete []attrd; return ATTRTYPEMISMATCH; } delete []attrd; return OK; }
Status Operators::SMJ(const string& result, // Output relation name const int projCnt, // Number of attributes in the projection const AttrDesc attrDescArray[], // Projection list (as AttrDesc) const AttrDesc& attrDesc1, // The left attribute in the join predicate const Operator op, // Predicate operator const AttrDesc& attrDesc2, // The left attribute in the join predicate const int reclen) // The length of a tuple in the result relation { cout << "Algorithm: SM Join" << endl; Status getRes = OK; HeapFile res = HeapFile(result, getRes); if(getRes != OK){ return getRes; } //sort the left relation //calculate the number of unpinned pages to use int k = .8 * (bufMgr->numUnpinnedPages()); //get the description of the relation & add up the size of all the attributes AttrDesc *relationStats; int numAttr, recSize = 0; attrCat->getRelInfo(attrDesc1.relName, numAttr, relationStats); for(int i = 0; i < numAttr; i++){ recSize += relationStats[i].attrLen; } //calculation the number of tuples (aka max items) with k pages available int numTuples = k * PAGESIZE / recSize; SortedFile left = SortedFile(attrDesc1.relName, attrDesc1.attrOffset, attrDesc1.attrLen, (Datatype)attrDesc1.attrType, numTuples, getRes); if (getRes != OK){ return getRes; } //now do same calculation to sort the right relation k = .8 * (bufMgr->numUnpinnedPages()); recSize = 0; attrCat->getRelInfo(attrDesc2.relName, numAttr, relationStats); for(int i = 0; i < numAttr; i++){ recSize += relationStats[i].attrLen; } numTuples = k * PAGESIZE / recSize; SortedFile right = SortedFile(attrDesc2.relName, attrDesc2.attrOffset, attrDesc2.attrLen, (Datatype)attrDesc2.attrType, numTuples, getRes); if (getRes != OK){ return getRes; } Record leftRec, rightRec, newRec; newRec.data = malloc(reclen); newRec.length = 0; RID leftRid, rightRid, newRecRID; Status leftIsGood = left.next(leftRec); if(leftIsGood != OK){ free(newRec.data); return leftIsGood; } Status rightIsGood = right.next(rightRec); if(rightIsGood != OK){ free(newRec.data); return rightIsGood; } while(rightIsGood == OK && leftIsGood == OK){ //compare the records int compare = matchRec(leftRec, rightRec, attrDesc1, attrDesc2); if(compare == 0){ while(compare == 0 && leftIsGood == OK){ right.setMark(); while(compare == 0 and rightIsGood == OK){ //project the joined tuple newRec.length = 0; for (int i = 0; i < projCnt; i++){ if (strcmp(attrDescArray[i].relName, attrDesc1.relName) == 0){ memcpy((char*)newRec.data + newRec.length, (char*)leftRec.data+attrDescArray[i].attrOffset, attrDescArray[i].attrLen); } else { memcpy((char*)newRec.data + newRec.length, (char*)rightRec.data+attrDescArray[i].attrOffset, attrDescArray[i].attrLen); } newRec.length += attrDescArray[i].attrLen; } //insert projected record into result res.insertRecord(newRec, newRecRID); //get next record and compare if next() works rightIsGood = right.next(rightRec); if(rightIsGood == OK){ compare = matchRec(leftRec, rightRec, attrDesc1, attrDesc2); } } right.gotoMark(); rightIsGood = right.next(rightRec); leftIsGood = left.next(leftRec); if(leftIsGood == OK && rightIsGood == OK){ compare = matchRec(leftRec, rightRec, attrDesc1, attrDesc2); } } } else if (compare < 0){ //scan the next on the left leftIsGood = left.next(leftRec); } else { rightIsGood = right.next(rightRec); } } free(newRec.data); return OK; }
HeapFile* IndexNestedLoopJoin(JoinSpec specOfR, JoinSpec specOfS) { Status status = OK; // Create a HeapFile for join results HeapFile* joinedFile = new HeapFile(NULL, status); if (OK != status) { cerr << "ERROR: cannot create a file for the joined relation.\n"; return NULL; } int recLenR = specOfR.recLen; int recLenS = specOfS.recLen; int recLenJoined = recLenR + recLenS; char* recR = new char[recLenR]; char* recS = new char[recLenS]; char* recJoined = new char[recLenJoined]; RecordID ridR, ridS, ridJoined; // Build the B+-tree index on the inner relation (S) Scan* scanS = specOfS.file->OpenScan(status); if (OK != status) { cerr << "ERROR: cannot open scan on the relation S heap file.\n"; return NULL; } BTreeFile* bTree = new BTreeFile(status, "IJBT", ATTR_INT, sizeof(int)); while (OK == scanS->GetNext(ridS, recS, recLenS)) { bTree->Insert(recS + specOfS.offset, ridS); } delete scanS; // Iterate through the outer relation (R) and join Scan* scanR = specOfR.file->OpenScan(status); if (OK != status) { cerr << "ERROR: cannot open scan on the relation R heap file.\n"; return NULL; } while (OK == scanR->GetNext(ridR, recR, recLenR)) { int* joinArgR = (int*)&recR[specOfR.offset]; BTreeFileScan* bTreeScan = (BTreeFileScan*)bTree->OpenSearchScan(joinArgR, joinArgR); int key; while (OK == bTreeScan->GetNext(ridS, &key)) { specOfS.file->GetRecord(ridS, recS, recLenS); MakeNewRecord(recJoined, recR, recS, recLenR, recLenS); joinedFile->InsertRecord(recJoined, recLenJoined, ridJoined); } delete bTreeScan; } // Release the allocated resources delete scanR; delete[] recR; delete[] recS; delete[] recJoined; delete bTree; return joinedFile; }
//--------------------------------------------------------------- // TupleNestedLoop::Execute // // Input: left - The left relation to join. // right - The right relation to join. // Output: out - The relation to hold the ouptut. // Return: OK if join completed succesfully. FAIL otherwise. // // Purpose: Performs a nested loop join on relations left and right // a tuple a time. You can assume that left is the outer // relation and right is the inner relation. //--------------------------------------------------------------- Status TupleNestedLoops::Execute(JoinSpec& left, JoinSpec& right, JoinSpec& out) { JoinMethod::Execute(left, right, out); // Create the temporary heapfile Status st; HeapFile *tmpHeap = new HeapFile(NULL, st); if (st != OK) { std::cerr << "Failed to create output heapfile." << std::endl; return FAIL; } // Open scan on left relation Status leftStatus; Scan *leftScan = left.file->OpenScan(leftStatus); if (leftStatus != OK) { std::cerr << "Failed to open scan on left relation." << std::endl; return FAIL; } // Loop over the left relation char *leftRec = new char[left.recLen]; while (true) { RecordID leftRid; leftStatus = leftScan->GetNext(leftRid, leftRec, left.recLen); if (leftStatus == DONE) break; if (leftStatus != OK) return FAIL; // The join attribute on left relation int *leftJoinValPtr = (int*)(leftRec + left.offset); // Open scan on right relation Status rightStatus; Scan *rightScan = right.file->OpenScan(rightStatus); if (rightStatus != OK) { std::cerr << "Failed to open scan on right relation." << std::endl; return FAIL; } // Loop over right relation char *rightRec = new char[right.recLen]; while (true) { RecordID rightRid; rightStatus = rightScan->GetNext(rightRid, rightRec, right.recLen); if (rightStatus == DONE) break; if (rightStatus != OK) return FAIL; // Compare join attribute int *rightJoinValPtr = (int*)(rightRec + right.offset); if (*leftJoinValPtr == *rightJoinValPtr) { // Create the record and insert into tmpHeap... char *joinedRec = new char[out.recLen]; MakeNewRecord(joinedRec, leftRec, rightRec, left, right); RecordID insertedRid; Status tmpStatus = tmpHeap->InsertRecord(joinedRec, out.recLen, insertedRid); if (tmpStatus != OK) { std::cerr << "Failed to insert tuple into output heapfile." << std::endl; return FAIL; } delete [] joinedRec; } } delete [] rightRec; delete rightScan; } out.file = tmpHeap; delete leftScan; delete [] leftRec; return OK; }
HeapFile* BlockNestedLoopJoin(JoinSpec specOfR, JoinSpec specOfS, int B) { Status status = OK; // Create a HeapFile for join results HeapFile* joinedFile = new HeapFile(NULL, status); if (OK != status) { cerr << "ERROR: cannot create a file for the joined relation.\n"; return NULL; } int recLenR = specOfR.recLen; int recLenS = specOfS.recLen; int recLenJoined = recLenR + recLenS; char* recBlockR = new char[B]; // Allocate memory for the block char* recS = new char[recLenS]; char* recJoined = new char[recLenJoined]; RecordID ridR, ridS, ridJoined; Scan* scanR = specOfR.file->OpenScan(status); if (OK != status) { cerr << "ERROR: cannot open scan on the relation R heap file.\n"; return NULL; } const int recordsPerBlock = B / recLenR; bool lastBlock = false; while (!lastBlock) { // Fill the block int i; for (i = 0; i < recordsPerBlock; i++) { if (OK != scanR->GetNext(ridR, recBlockR + i*recLenR, recLenR)) { lastBlock = true; break; } } int lastRecordIndex = i; Scan* scanS = specOfS.file->OpenScan(status); if (OK != status) { cerr << "ERROR: cannot open scan on the relation S heap file.\n"; return NULL; } while (OK == scanS->GetNext(ridS, recS, recLenS)) { int* joinArgS = (int*)&recS[specOfS.offset]; for (int currentRecordIndex = 0; currentRecordIndex < lastRecordIndex; currentRecordIndex++) { char* currentRecordPtr = recBlockR + (currentRecordIndex * recLenR); int* joinArgR = (int*)(currentRecordPtr + specOfR.offset); if (*joinArgR == *joinArgS) { MakeNewRecord(recJoined, currentRecordPtr, recS, recLenR, recLenS); joinedFile->InsertRecord(recJoined, recLenJoined, ridJoined); } } } delete scanS; } // Release the allocated resources delete scanR; delete[] recBlockR; delete[] recS; delete[] recJoined; return joinedFile; }
Status Operators::INL(const string& result, // Name of the output relation const int projCnt, // Number of attributes in the projection const AttrDesc attrDescArray[], // The projection list (as AttrDesc) const AttrDesc& attrDesc1, // The left attribute in the join predicate const Operator op, // Predicate operator const AttrDesc& attrDesc2, // The right attribute in the join predicate (INDEXED) const int reclen) // Length of a tuple in the output relation { cout << "Algorithm: Indexed NL Join" << endl; AttrDesc* r; int num; Status status = attrCat->getRelInfo(result, num, r); if(status != OK) return status; // Load heap 1 HeapFileScan heap1 = HeapFileScan(attrDesc1.relName, status); if (status != OK) return status; // Load heap 2 HeapFileScan heap2 = HeapFileScan(attrDesc2.relName, status); if (status != OK) return status; // Open output heap HeapFile heapOut = HeapFile(result, status); if (status != OK) return status; // Get size of output record int size = 0; for (int x = 0; x < projCnt; x++) { size += attrDescArray[x].attrLen; } // Create/find the index (checked to ensure indexed before entering this fn) Index index = Index(attrDesc2.relName, attrDesc2.attrOffset, attrDesc2.attrLen, (Datatype)attrDesc2.attrType, 1, status); if (status != OK) return status; //Start Join RID rid, rid1, rid2; Record record1, record2; while(heap1.scanNext(rid1, record1) == OK) { char* data1 = (char *) record1.data; // Update Heapfile Scan for Next Loop heap2 = HeapFileScan(attrDesc2.relName, status); if(status != OK) return status; // Restart the Index Scan for Next Loop status = index.startScan((char *) record1.data + attrDesc1.attrOffset); if(status != OK) return status; while(index.scanNext(rid2) == OK) { status = heap2.getRandomRecord(rid2, record2); if(status != OK) return status; char* data2 = (char *) record2.data; // Compare the values stored in both records int valueDif = matchRec(record1, record2, attrDesc1, attrDesc2); if(!valueDif) { // Add to output heap Record record; record.data = malloc(size); record.length = size; //Need to check through attrDescArray to find outside heap attrDescs for(int i = 0; i < projCnt; i++) { AttrDesc tempAttr = attrDescArray[i]; //Insert from attrDesc1 if( !strcmp(attrDesc1.relName, tempAttr.relName)) { memcpy(((char*) record.data) + r[i].attrOffset, data1 + tempAttr.attrOffset, tempAttr.attrLen); } else { memcpy(((char*) record.data) + r[i].attrOffset, data2 + tempAttr.attrOffset, tempAttr.attrLen); } } // Now insert the record into the output status = heapOut.insertRecord(record, rid); if(status != OK) return status; } } // End the scan and restart it again next iteration status = index.endScan(); if(status != OK) return status; } status = heap1.endScan(); if(status != OK) return status; return OK; }
//--------------------------------------------------------------- // BlockNestedLoop::Execute // // Input: left - The left relation to join. // right - The right relation to join. // Output: out - The relation to hold the ouptut. // Return: OK if join completed succesfully. FAIL otherwise. // // Purpose: Performs a block nested loops join on the specified relations. // You can find a specification of this algorithm on page 455. You should // choose the smaller of the two relations to be the outer relation, but you // should make sure to concatenate the tuples in order <left, right> when // producing output. The block size can be specified in the constructor, // and is stored in the variable blockSize. //--------------------------------------------------------------- Status BlockNestedLoops::Execute(JoinSpec& left, JoinSpec& right, JoinSpec& out) { JoinMethod::Execute(left, right, out); Status s; HeapFile* tmpHeap = new HeapFile(NULL, s); if (s != OK) { std::cout << "Creating new Heap File Failed" << std::endl; return FAIL; } Scan * leftScan = left.file->OpenScan(s); if (s != OK) { std::cout << "Open scan left failed" << std::endl; return FAIL; } Scan * rightScan = right.file->OpenScan(s); if (s != OK) { std::cout << "Open scan left failed" << std::endl; return FAIL; } RecordID leftRid, rightRid, rightFirstRid, outRid; // array to hold the "block" in memory char* blockArray = new char[left.recLen * blockSize]; int blockArraySize = 0; // size in case of half full block int* leftCurrRec = (int *)blockArray; int* leftRec = new int[left.numOfAttr]; int* rightRec = new int[right.numOfAttr]; int leftRecLen = left.recLen; int rightRecLen = right.recLen; char* newRec = new char[left.recLen + right.recLen]; rightFirstRid = rightScan->currRid; Status st = OK; while (true) { // fill the block with as many records as possible if (blockArraySize < blockSize) { st = leftScan->GetNext(leftRid, (char *)leftRec, leftRecLen); if (st != DONE) { memcpy(blockArray + left.recLen * blockArraySize, leftRec, left.recLen); blockArraySize++; continue; } } // scan through the right, and scan the block in memory for joins while (rightScan->GetNext(rightRid, (char *)rightRec, rightRecLen) != DONE) { for (int j = 0; j < blockSize; j++) { if (j >= blockArraySize) { break; } leftCurrRec = (int *) (blockArray + left.recLen * j); if (leftCurrRec[left.joinAttr] == rightRec[right.joinAttr]) { MakeNewRecord(newRec, (char *)leftCurrRec, (char *)rightRec, left, right); tmpHeap->InsertRecord(newRec, left.recLen + right.recLen, outRid); } } } rightScan->MoveTo(rightFirstRid); blockArraySize = 0; if (st == DONE) { break; } } out.file = tmpHeap; //std::cout << "NUM BNL: " << tmpHeap->GetNumOfRecords() << std::endl; delete leftScan; delete rightScan; delete blockArray; delete leftRec; delete rightRec; delete newRec; return OK; }
//------------------------------------------------------------------- // Sort::PassZero // // Input : None // Output : Number of temp files generated after this pass // Return : OK if Pass 0 succeeds, FAIL otherwise //------------------------------------------------------------------- Status Sort::PassZero(int &numTempFiles) { // Get input file Status status; HeapFile inputFile(_inFile, status); if (status != OK) return ReturnFAIL("Opening input file in PassZero function failed."); int numRecords = inputFile.GetNumOfRecords(); int recCounter = 0, globalRecCounter = 0; // Allocate memory int areaSize = MINIBASE_PAGESIZE * _numBufPages; char *area = (char *)malloc(areaSize); char *areaPtr = area; RecordID rid; char *recPtr = (char *)malloc(_recLength); int recLen = _recLength; int numRecForSort = std::min(areaSize/_recLength,numRecords); // number of rec in sorting area at once // Open Scan Scan *scan = inputFile.OpenScan(status); if (status != OK) return ReturnFAIL("Opening scan in PassZero function failed."); // Sort passZeroRuns = 0; if (areaSize >= _recLength) { // can fit at least one record while (scan->GetNext(rid,recPtr,recLen) == OK) { recCounter++; globalRecCounter++; // add to memory if (memcpy(areaPtr,recPtr,recLen) != areaPtr) return ReturnFAIL("Reading records to memory in PassZero function failed."); areaPtr += recLen; areaSize -= recLen; if (areaSize < _recLength || globalRecCounter == numRecords) { // can't fit another rec or all recs have been added // sort switch (_sortType) { case attrInteger: std::qsort(area,recCounter,_recLength,CompareInt); break; case attrString: std::qsort(area,recCounter,_recLength,CompareString); default: break; } // write out char *fileName = CreateTempFilename(_outFile,0,passZeroRuns); passZeroRuns++; HeapFile *tempFile = new HeapFile(fileName,status); if (status != OK) return ReturnFAIL("Opening temp file in PassZero function failed."); areaPtr = area; while (recCounter > 0) { // insert tempFile->InsertRecord(areaPtr,_recLength,rid); recCounter--; areaPtr += _recLength; } numTempFiles++; areaSize = MINIBASE_PAGESIZE * _numBufPages; areaPtr = area; // reset delete fileName; delete tempFile; } } } free(area); free(recPtr); delete scan; return OK; }