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; }
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; }
//--------------------------------------------------------------- // 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; }
//--------------------------------------------------------------- // 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; }